﻿/*
 * Rappelz: Endless Odyssey - The first free open source Rappelz server emulator
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rappelz.GameServer.Scripting;

namespace Rappelz.GameServer
{
    public interface IMonsterDeleteHandler
    {
        void onMonsterDelete(Monster mob);
    }

    public class Monster : Creature
    {
        public class MonsterDeleteHander
        {
            // UserDefinedType:   MonsterDeleteHandler
            // VTable         :     , Type:  *
            // Function       :     public void onMonsterDelete(struct StructMonster *)
            // Function       :     public void MonsterDeleteHandler(const struct StructMonster::MonsterDeleteHandler &)
            // Function       :     public void MonsterDeleteHandler()
            // Function       :     public struct StructMonster::MonsterDeleteHandler & operator=(const struct StructMonster::MonsterDeleteHandler &)
        }

        public class VirtualParty
        {
            public VirtualParty(int id, int d, int lv)
            {
                this.fContribute = 0.0f;
                this.hPlayer = 0;
                this.nPartyID = id;
                this.nDamage = d;
                this.nLevel = lv;
                this.bTamer = false;
            }

            public VirtualParty(uint h, int d, int lv)
            {
                this.fContribute = 0.0f;
                this.hPlayer = h;
                this.nPartyID = 0;
                this.nDamage = d;
                this.nLevel = lv;
                this.bTamer = false;
            }

            public int nPartyID;// Data           :     this+0x0, Member, Type: int, 
            public uint hPlayer;// Data           :     this+0x4, Member, Type: unsigned int, 
            public int nDamage;// Data           :     this+0x8, Member, Type: int, 
            public float fContribute;// Data           :     this+0xC, Member, Type: float, 
            public bool bTamer;// Data           :     this+0x10, Member, Type: bool, 
            public int nLevel;// Data           :     this+0x14, Member, Type: int, 

            public static bool greaterByDamage(VirtualParty lh, VirtualParty rh)
            {
                return lh.nDamage > rh.nDamage;
            }

            public static bool greaterByContribute(VirtualParty lh, VirtualParty rh)
            {
                return rh.fContribute < lh.fContribute;
            }
        }

        public class VirtualPartySorter : IComparer<VirtualParty>
        {
            public enum VirtualPartySorterOptions
            {
                Damage,
                Contribute,
            }

            private VirtualPartySorterOptions _sortOption = VirtualPartySorterOptions.Damage;


            protected VirtualPartySorter()
            {
            }

            // 4. Create a constructor that specifies the desired sort option
            public VirtualPartySorter(VirtualPartySorterOptions sortOption)
            {
                _sortOption = sortOption;
            }
            // 5. Write the Compare method with a switch statement
            public int Compare(VirtualParty lh, VirtualParty rh)
            {
                // Use the _sortOption field to determine the property to Compare
                switch (_sortOption)
                {
                    case VirtualPartySorterOptions.Damage:
                        return lh.nDamage.CompareTo(rh.nDamage);

                    default:
                        return lh.fContribute.CompareTo(rh.fContribute);
                }
            }
        }


        public class calcPartyContributePartyDamage
        {
            public calcPartyContributePartyDamage(int damage, int level)
            {
                nDamage = damage;
                nLevel = level;
            }
            public calcPartyContributePartyDamage()
            {

            }

            public int nDamage;
            public int nLevel;
        }


        public enum MonsterGenerateCode : int
        {
            None = 0,
            ByRespawn = 1,
            ByScript = 2,
            ByShoveling = 3,
        }

        public enum MonsterStatus : int
        {
            Normal = 0,
            Tracking = 1,
            FindAttackPos = 2,
            Attack = 3,
            Dead = 4,
        }

        public const int ITEM_DROP_LENGTH = 18;
 

        public static Monster AllocMonster(uint idx)
        {
//             unsigned int v1; // esi@1
//             unsigned int v2; // ecx@1
//             FileLogHandler *v3; // eax@2
//             StructMonster *result; // eax@2
//             signed int v5; // esi@3
//             int v6; // edx@4
//             GameAllocateFunctor _fo; // [sp+4h] [bp-8h]@1
//             unsigned int v8; // [sp+8h] [bp-4h]@1
// 
//             v1 = idx;
//             _fo.vfptr = &::::_myIntializer::_vftable_;
//             v8 = idx;

            Monster mob = MemoryPool.AllocMonster(idx);
            if (mob == null)
                return null;

            if (mob.m_pContentInfo != null)
            {
                foreach (MonsterBase.MonsterSkillInfo si in mob.m_pContentInfo.skill_info)
                {
                    if(si.skill_id != 0)
                    {
                        mob.SetSkill(-3, si.skill_id, si.skill_lvl, 0);
                    }
                }
                mob.CalculateStat();
                mob.m_nHP = mob.m_nMaxHP;
                mob.m_fMP = mob.m_nMaxMP;
            }
            return mob;
        }

        public Monster(uint handle, MonsterBase mb)
        {
            uint ct = Globals.GetArTime();
            this.m_nRegenTime = ct;
            this.m_bRespawnByScript = false;
            this.m_nArObjectType = 1;
            this.m_nStatus = 0;
            this.m_bComeBackHome = false;
            this.SetMonsterInfo(mb);
            this.m_nLastTrackTime = 0;
            this.m_nTotalDamage = 0;
            this.m_nStatus = 0;
            this.m_nGenerateCode = 0;
            this.m_pDeleteHandler = null;
            this.m_nDungeonId = 0;
            this.m_bIsDungeonRaidMonster = false;
            this.m_bIsDungeonOwnerGuardian = false;
            this.m_bIsDungeonSiegerGuardian = false;
            this.m_nHuntaholicRespawnID = 0;
            this.m_hFirstAttacker = 0;
            this.m_nFirstAttackTime = 0;
            this.m_nHateCheckTime = 0;
            this.m_nTamedTime = -1;
            this.m_RespawnY = 0.0f;
            this.m_RespawnX = 0.0f;
            this.m_bNeedToFindEnemy = false;
            this.m_nLastEnemyDistance = 0.0f;
            this.m_hTamer = 0;
            this.m_nMaxHate = 0;
            this.m_bTamedSuccess = false;
            this.m_nLastHateUpdateTime = 0;
            this.m_bIsWandering = true;
            this.mv.face = (float) (Globals.GetRandomInt32() / 100);
//            this.m_pWayPointInfo = 0;
            this.m_nWayPointIdx = 0;
//            this.m_pRoamer = 0;
            this.m_bContinueAttack = false;
        }
// Function       :   public static void StructMonster::FreeMonster(struct StructMonster *)
// Function       :   public unsigned int StructMonster::GetHandle()

        public override string GetName()
        {
            return GameContent.GetString(this.m_pContentInfo.name_id);
        }

        public override int GetCreatureGroup()
        {
            return this.m_pContentInfo.group;
        }
// Function       :   public void SetGenerateCode(int)
// Function       :   public void SetDeleteHandler(struct StructMonster::MonsterDeleteHandler *)
// Function       :   public const struct StructMonster::MonsterDeleteHandler * GetDeleteHandler()
// Function       :   public void SetReturnPosition(float, float)
// Function       :   public const struct ArPosition GetReturnPosition()

        public void SetMonsterInfo(MonsterBase info)
        {
            this.m_nLevel = info.level;
            this.m_pContentInfo = info;
            CreatureStat stat = GameContent.GetStatInfo(info.stat_id);
            this.m_Stat = new CreatureStat();
            this.m_Stat.Copy(stat);
        }

        public override bool IsMonster()
        {
            return true;
        }

        public bool IsEnvironmentMonster()
        {
            return this.m_pContentInfo.fight_type == 1;
        }

        public override bool IsBattleMode()
        {
            return this.m_nStatus == 1 || this.m_nStatus == 3 || this.m_nStatus == 2;
        }

        public bool IsBossMonster()
        {
            return this.m_pContentInfo.monster_type >= 22;
        }
// Function       :   public int GetMonsterType()

        public bool IsDungeonConnector()
        {
            return this.m_pContentInfo.race == 20001;
        }

        public bool IsAgent()
        {
            return this.m_pContentInfo.fight_type == 4;
        }

        public bool IsAutoTrap()
        {
            return this.m_pContentInfo.fight_type == 5;
        }

        public bool IsNonAttacker()
        {
            return this.m_pContentInfo.fight_type == 6 || this.m_pContentInfo.attack_point == 0;
        }

// Function       :   public bool StructMonster::IsDungeonCore()

        public float GetChaseRange()
        {
            return (12 * this.m_pContentInfo.chase_range);
        }
// Function       :   public int GetDungeonId()
// Function       :   public bool IsDungeonRaidMonster()
// Function       :   public bool IsOriginalDungeonSiegerGuardian()
// Function       :   public bool IsOriginalDungeonOwnerGuardian()
// Function       :   public void SetDungeonOwnerGuardian()
// Function       :   public void SetDungeonSiegerGuardian()
// Function       :   public void ResetDungeonOwnerGuardian()
// Function       :   public void ResetDungeonSiegerGuardian()
// Function       :   public void SetDungeonRaidMonster()
// Function       :   public void SetDungeonId(int)
// Function       :   public int GetHuntaholicRespawnID()
// Function       :   public void SetHuntaholicRespawnID(const int)

        public float GetFirstAttackRange()
        {
            return this.m_pContentInfo.visible_range;
        }

        public override bool IsEnemy(Creature pTarget, bool bIncludeHiding)
        {
            bool result;

            result = base.IsEnemy(pTarget, bIncludeHiding);
            if (result)
                result = !pTarget.IsNPC();
            return result;
        }
        
        public override bool IsAlly(Creature pTarget)
        {
            Player p;

            if (pTarget.IsMonster())
                return true;
            if (!this.m_bIsDungeonOwnerGuardian && !this.m_bIsDungeonSiegerGuardian)
                return base.IsAlly(pTarget);
            if (pTarget.IsPlayer())
            {
                p = pTarget as Player;
            }
            else
            {
                if (!pTarget.IsSummon())
                    return base.IsAlly(pTarget);
                p = (pTarget as Summon).m_master;
            }
            if (p != null && p.m_nPartyId != 0)
            {
                int d_id = DungeonManager.Instance.GetDungeonID(this.mv.x, this.mv.y);
                if (d_id != 0)
                {
                    bool r = PartyManager.Instance.GetAttackTeamGuildID(p.m_nPartyId) == DungeonManager.Instance.GetOriginalOwnGuildID(d_id) ? !this.m_bIsDungeonOwnerGuardian : !this.m_bIsDungeonSiegerGuardian;
                    if (!r)
                        return true;
                }
            }
            return base.IsAlly(pTarget);
}

        public bool IsFirstAttacker()
        {
            return (this.m_pContentInfo.attack_type & 1) != 0 && GameRule.bRedNameMobsFirstAttack;
        }
// Function       :   public bool IsGroupRevenger()

        public bool IsGroupFirstAttacker()
        {
            return (this.m_pContentInfo.attack_type & 2) != 0;
        }

        public bool IsCastRevenger()
        {
            return (this.m_pContentInfo.attack_type & 4) != 0;
        }

        public bool IsBattleRevenger()
        {
            return (this.m_pContentInfo.attack_type & 0x10) != 0;
        }

        public int GetMonsterGroup()
        {
            return this.m_pContentInfo.monster_group;
        }
// Function       :   public bool IsTameable()

        public int GetTameItemCode()
        {
            int result;

            result = this.m_pContentInfo.taming_code;
            if (result != 0)
                result = GameContent.GetSummonInfo(this.m_pContentInfo.taming_code).card_id;
            return result;
        }

        public int GetTameCode()
        {
            return this.m_pContentInfo.taming_code;
        }

        public float GetTamePercetage()
        {
            return this.m_pContentInfo.taming_percentage;
        }
// Function       :   public float GetTameExpAdjust()

        public override float GetScale()
        {
            return this.m_pContentInfo.scale;
        }

        public override float GetSize()
        {
            return this.m_pContentInfo.size;
        }

        public MonsterStatus GetStatus()
        {
            return (MonsterStatus) this.m_nStatus;
        }

        public void SetStatus(MonsterStatus status)
        {
            if (this.m_nStatus != (int)MonsterStatus.Dead)
            {
                if ((int)status != this.m_nStatus && (int)status != 4 && (int)status != 0 && this.m_nStatus == 0)
                    this.ResetTriggerCondition();
                if (this.m_nStatus == (int)status)
                {
                    this.m_nStatus = (int)status;
                }
                else
                {
                    this.m_nStatus = (int)status;
                    Messages.BroadcastStatusMessage(this);
                }
            }
        }
// Function       :   public void SetNeedToFindEnemy(bool)

        public override bool StartAttack(uint target, bool bNeedFastReaction)
        {
            bool result;
            if (base.StartAttack(target, bNeedFastReaction))
            {
                this.SetStatus(MonsterStatus.Attack);
                result = true;
            }
            else
            {
                result = false;
            }
            return result;
        }


        public override int onDamage(Creature pFrom, Elemental.Type elementalType, Creature.DamageType damageType, int nDamage, bool bCritical)
        {
            Player player = null;
            Summon summon = null;

            if (this.m_nHP - nDamage <= 0)
                nDamage = this.m_nHP;

            if (nDamage == 0)
                return base.onDamage(pFrom, elementalType, damageType, 0, bCritical);
            uint ct = Globals.GetArTime();

            if (this.m_hFirstAttacker == 0)
            {
                if (pFrom.IsSummon())
                {
                    summon = pFrom as Summon;
                    if (summon.m_master != null)
                    {
                        player = summon.m_master;
                    }
                }
                else
                {
                    player = pFrom as Player;
                }
                if(player != null)
                    this.m_hFirstAttacker = player.m_hHandle;
                this.m_nFirstAttackTime = ct;
            }

            if(pFrom.IsSummon())
            {
                summon = pFrom as Summon;
                player = summon.m_master;
            }
            else
            {
                player = pFrom as Player;
            }

            this.addDamage(pFrom.m_hHandle, nDamage);
            if (player != null && this.m_hTamer == player.m_hHandle)
                this.m_nTamedTime += (int)(ct + 30000);
            return base.onDamage(pFrom, elementalType, damageType, nDamage, bCritical);
        }


        public int GetMonsterId()
        {
            return m_pContentInfo.uid;

        }

        public override CreatureStat GetBaseStat()
        {
            return GameContent.GetStatInfo(this.m_pContentInfo.stat_id);
        }

// Function       :   public int StructMonster::GetLevel()

        public override byte GetRace()
        {
            return (byte) m_pContentInfo.race;
        }
// Function       :   public int StructMonster::GetHate(unsigned int)

        public int AddHate(uint handle, int pt, bool bBroadcast, bool bProcRoamingMonster)
        {
            List<uint> vResult = new List<uint>();              // -56  -38h
            int nHate;                                          // -16  -10h

            if (this.m_nHP == 0 || this.m_pContentInfo.fight_type == 1)
                return 0;
            uint ct = Globals.GetArTime();
            Creature cr = Creature.get(handle) as Creature;

            if (cr == null || !this.IsEnemy(cr, false))
                return 0;

            HateTag ht = this.addHate(handle, pt);

            nHate = ht.nHate;
            if (cr != null)
            {
                if (this.m_pRoamer != null && bProcRoamingMonster)
                {
                    this.m_pRoamer.PendHateShare(this.m_hHandle, cr.m_hHandle, (int)(this.m_fHateRatio * pt), 4);
                }
            }
            if (pt >= 0 )
            {
                if (bBroadcast)
                {
                    if ( ((this.m_pContentInfo.attack_type >> 3) & 1) != 0)
                    {
                        if (this.m_pRoamer == null)
                        {
                            RappelzServer.Instance.EnumMovableObject(this.mv, this.m_layer, this.m_pContentInfo.visible_range * 0.8f, vResult, false, true);

                            foreach (uint h in vResult)
                            {
                                Monster mob = GameObject.raw_get(h) as Monster;
                                if (mob != null && mob.IsMonster() && !ReferenceEquals(mob,this))
                                {
                                    if (mob.m_pContentInfo.monster_group == this.m_pContentInfo.monster_group)
                                        mob.AddHate(handle, (int)(this.m_fHateRatio * pt),false,true);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                this.findNextEnemy();
            }
            return nHate;
        }

// Function       :   public int StructMonster::RemoveHate(unsigned int, int)
// Function       :   public unsigned int GetEnemyUID()
// Function       :   public unsigned int StructMonster::GetMaxDamageAdder()

        public override void OnUpdate()
        {
            if (this.m_bNeedToFindEnemy)
            {
                this.m_bNeedToFindEnemy = false;
                this.findNextEnemy();
            }
            base.OnUpdate();

        }

        public uint GetTamer()
        {
            return m_hTamer;
        }

        public void SetTamer(uint handle, int nTamingSkillLevel)
        {
            this.m_hTamer = handle;
            this.m_nTamedTime = (int)Globals.GetArTime();
            this.m_nTamingSkillLevel = nTamingSkillLevel;
        }

// Function       :   public int GetTamingSkillLevel()
// Function       :   public bool IsTamingSuccessed()
// Function       :   public void SetWandering(bool)
// Function       :   public bool StructMonster::IsAttackable()
// Function       :   public bool StructMonster::IsMovable()
// Function       :   public bool StructMonster::IsKnockbackable()
// Function       :   public void SetContinueAttack(bool)
// Function       :   public bool IsNeedToContinueAttack()
// Function       :   public const struct MonsterBase * GetMonsterBase()
// Function       :   public void SetRespawnByScript()
// Function       :   public void SetWayPointInfo(const struct GameContent::WAY_POINT_INFO *)
// Function       :   public void SetRoamer(struct StructRoamer *)
// Function       :   public struct StructRoamer * GetRoamer()
// Function       :   public void StructMonster(const struct StructMonster &)
// Function       :   protected void StructMonster::StructMonster(unsigned int, unsigned int)
// Function       :   protected void StructMonster::~StructMonster()
// Function       :   protected bool StructMonster::ProcDelete()

        public override void onProcess(int nThreadIdx)
        {
            uint ct = Globals.GetArTime();
            MonsterStatus ms = this.GetStatus();
            if (ms != MonsterStatus.Normal)
            {
                if ((int)ms > 0)
                {
                    if ((int)ms <= 3 )
                    {
//                         buf[59] = 789;
//                         buf[58] = "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp";
//                         buf[57] = 789;
//                         buf[56] = "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp";
//                         buf[55] = v2;
//                         buf[54] = &result;
//                         v8 = RappelzServer.Instance._LockObjectWithVisibleRange(buf[54], this);
//                        ArcadiaAutoLock::ArcadiaAutoLock(&thisa, v8, buf[58], &buf[59]->handle);

                        if (this.m_nLastUpdateTime + 50 < ct)
                            this.OnUpdate();

//                        ArcadiaAutoLock::_ArcadiaAutoLock(&thisa);
                        if (this.IsActable())
                        {
                            if (this.m_nHP == 0)
                                return;

                            if (this.m_pRoamer != null && this.m_pRoamer.m_eRoamingStatus != Roamer.RoamingStatus.Paused)
                            {
                                this.m_pRoamer.PauseRoaming();
                                this.m_pRoamer.PendHateShare(this.m_hHandle, this.m_hEnemy, 1, 6);
                            }
                            else
                            {
                                this.AI_processAttack(ct);
                            }
                        }
                    }
                    else
                    {
                        if (ms == MonsterStatus.Dead)
                        {
                            this.processDead(ct);
                            return;
                        }
                    }
                }
            }
            else 
            {
                if (this.m_pRoamer != null)
                {
                    if (this.priority != Priority.High)
                        RappelzServer.Instance.SetObjectPriority(this, SchedulerObject.Priority.High);
                }
                else
                {
                    if ((this.m_StatusFlag & StatusFlags.MovePending) == 0 && this.priority >= SchedulerObject.Priority.Normal)
                        RappelzServer.Instance.SetObjectPriority(this, SchedulerObject.Priority.Normal);
                }

                if (this.m_nLastUpdateTime + 3000 < ct || (this.m_StatusFlag & StatusFlags.MovePending) != 0)
                {
//                     buf[59] = 766;
//                     buf[58] = "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp";
//                     buf[57] = 766;
//                     buf[56] = "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp";
//                     buf[55] = v2;
//                     buf[54] = &v30;
//                     v15 = ArcadiaServer::Instance();
//                     v16 = ArcadiaServer::_LockObjectWithVisibleRange(v15, buf[54], buf[55], buf[56], &buf[57]->handle);
//                     ArcadiaAutoLock::ArcadiaAutoLock(&_lock, v16, buf[58], &buf[59]->handle);
                    this.OnUpdate();

                    if (this.m_nHP == 0)
                    {
//                        ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                        return;
                    }
                    if (this.m_nMaxHP == this.m_nHP)
                        this.clearHateList();
//                    ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                }
                if (this.bIsInWorld && this.IsActable() && (this.m_bIsDungeonRaidMonster || !this.m_bComeBackHome))
                    this.processFirstAttack(ct);
                if (this.bIsInWorld && this.IsActable() && this.IsMovable() && !this.m_bComeBackHome)
                    this.processMove(ct);

            }

            if (this.m_nHP != 0)
            {
                if ((this.m_StatusFlag & StatusFlags.MovePending) != 0)
                {
//                     buf[59] = 817;
//                     buf[58] = "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp";
//                     buf[57] = 817;
//                     buf[56] = "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp";
//                     buf[55] = v2;
//                     buf[54] = &t;
//                     v19 = ArcadiaServer::Instance();
//                     v20 = ArcadiaServer::_LockObjectWithVisibleRange(v19, buf[54], buf[55], buf[56], &buf[57]->handle);
//                     ArcadiaAutoLock::ArcadiaAutoLock(&v25, v20, buf[58], &buf[59]->handle);
                    if (this.bIsInWorld)
                        this.processPendingMove();
//                    ArcadiaAutoLock::_ArcadiaAutoLock(&v25);
                }
                if (this.m_nLastHateUpdateTime < ct + 6000 )
                {
//                     buf[59] = 823;
//                     buf[58] = "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp";
//                     buf[57] = 823;
//                     buf[56] = "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp";
//                     buf[55] = v2;
//                     buf[54] = &v29;
//                     v22 = ArcadiaServer::Instance();
//                     v23 = ArcadiaServer::_LockObjectWithVisibleRange(v22, buf[54], buf[55], buf[56], &buf[57]->handle);
//                     ArcadiaAutoLock::ArcadiaAutoLock(&v26, v23, buf[58], &buf[59]->handle);
                    this.m_nLastHateUpdateTime = ct;
                    this.updateHate();
//                    ArcadiaAutoLock::_ArcadiaAutoLock(&v26);
                }
                if (this.m_nTamedTime + 30000 < ct)
                {
                    this.m_hTamer = 0;
                    this.m_nTamedTime = -1;
                }
                if (this.mv.bIsMoving && this.bIsInWorld )
                {
                    if (this.IsMovable())
                        this.processWalk(ct);
                }
            }

        }
// Function       :   protected void StructMonster::regenHPMP(uint t)

        protected bool CheckTriggerCondition(int idx)
        {
            uint ct = Globals.GetArTime();

            if (this.m_pContentInfo.trigger[idx].id == 0)
                return false;

            if (this.m_pContentInfo.trigger[idx].id > 1)
            {
                if (this.m_pContentInfo.trigger[idx].id > 2)
                {
                    if (this.m_pContentInfo.trigger[idx].id > 3)
                    {
                        if (this.m_pContentInfo.trigger[idx].id == 4)
                        {
                            if (ct > this.m_pContentInfo.trigger[idx].value[0] * 100.0f + this.m_vTriggerFlag[idx])
                            {
                                this.m_vTriggerFlag[idx] = (int)ct;
                                return true;
                            }
                            return false;
                        }
                        if (this.m_pContentInfo.trigger[idx].id == 5)
                        {
                            if (this.m_vTriggerFlag[idx] == 0)
                            {
                                this.m_vTriggerFlag[idx] = (int)ct;
                                return true;
                            }
                            if (ct > this.m_pContentInfo.trigger[idx].value[0] * 100.0f + this.m_vTriggerFlag[idx])
                            {
                                this.m_vTriggerFlag[idx] = (int)ct;
                                return true;
                            }
                            return false;
                        }
                    }
                    else
                    {
                        // must be 3
                        if (this.m_vTriggerFlag[idx] != 0 && Globals.GetArTime() > this.m_pContentInfo.trigger[idx].value[0] * 100.0 + this.m_vTriggerFlag[idx])
                        {
                            this.m_vTriggerFlag[idx] = 0;
                            return true;
                        }
                    }
                }
                else
                {
                    // must be 2
                    if (this.m_pContentInfo.trigger[idx].value[0] >= this.GetHPPercentage() && this.m_pContentInfo.trigger[idx].value[1] * 10000.0 > Globals.GetRandomInt32(0, 9999) )
                        return true;
                }
                return false;
            }

            // must be 1
            if (this.m_vTriggerFlag[idx] != 0 || this.m_pContentInfo.trigger[idx].value[0] < this.GetHPPercentage())
                return false;
            return true;

        }

        protected bool ResetTriggerCondition()
        {
            for(int i = 0; i < MonsterBase.NUMBER_OF_TRIGGERS; ++i)
            {
                MonsterBase.MonsterTrigger t = this.m_pContentInfo.trigger[i];
                switch(t.id)
                {
                    case (int)MonsterBase.TriggerType.HPBelowOnce:
                        if (t.value[0] <= this.GetHPPercentage())
                            this.m_vTriggerFlag[i] = 0;
                        break;

                    case (int)MonsterBase.TriggerType.TimeOnce:
                    case (int)MonsterBase.TriggerType.TimeAlways:
                        this.m_vTriggerFlag[i] = (int)Globals.GetArTime();
                        break;

                    case (int)MonsterBase.TriggerType.TimeAlwaysIncludeStart:
                        this.m_vTriggerFlag[i] = 0;
                        break;

                }
            }
            return true;

        }

        protected void AI_processAttack(Creature pEnemy, uint t)
        {

// .text:0048CF7A var_344         = byte ptr -344h
// .text:0048CF7A var_334         = byte ptr -334h
// .text:0048CF7A var_324         = byte ptr -324h
            ArPosition stopPosition;//    = ArPosition ptr -314h
//.text:0048CF7A var_304         = byte ptr -304h
            ArPosition newPos;//          = ArPosition ptr -2F4h
//.text:0048CF7A var_2E4         = ArPosition ptr -2E4h
            ArPosition pos;//             = ArPosition ptr -2D4h
            ArPosition homePosition = new ArPosition();//    = ArPosition ptr -2C4h
            ArPosition enemyPosition;//   = ArPosition ptr -2B4h
            ArPosition attack_pos;//      = ArPosition ptr -2A4h
// .text:0048CF7A vPath           = std::vector<X2D::Point<int>,std::allocator<X2D::Point<int> > > ptr -294h
// .text:0048CF7A ptEnd           = X2D::Point<int> ptr -284h
// .text:0048CF7A var_27C         = dword ptr -27Ch
// .text:0048CF7A end             = std::_Vector_iterator<X2D::Polygon<int> *,std::allocator<X2D::Polygon<int> *> > ptr -278h
// .text:0048CF7A var_26C         = dword ptr -26Ch
// .text:0048CF7A begin           = std::_Vector_iterator<X2D::Polygon<int> *,std::allocator<X2D::Polygon<int> *> > ptr -268h
            bool bDoubleAttack;// .text:0048CF7A bDoubleAttack   = dword ptr -25Ch
            ArPosition targetPosition = new ArPosition();//  = ArPosition ptr -258h
// .text:0048CF7A _lock           = ArcadiaAutoLock ptr -248h
            ArPosition myPosition;//      = ArPosition ptr -234h
            List<uint> vList = new List<uint>();// .text:0048CF7A vList           = std::vector<unsigned int,std::allocator<unsigned int> > ptr -224h
// .text:0048CF7A var_214         = qword ptr -214h
// .text:0048CF7A __lock          = ArcadiaLock ptr -20Ch
// .text:0048CF7A it              = std::_Vector_iterator<unsigned int,std::allocator<unsigned int> > ptr -208h
// .text:0048CF7A result          = ArcadiaLock ptr -1FCh
            uint rx2;                           // -504   -1F8h
            uint ry2;
// .text:0048CF7A var_1F1         = byte ptr -1F1h
// .text:0048CF7A var_1F0         = dword ptr -1F0h
// .text:0048CF7A this            = dword ptr -1ECh
            float ry1;                           // -488   -1E8h
            int nPrevStatus;//     = dword ptr -1E4h
            float fMod;//            = dword ptr -1E0h
            float rx1;                           // -476   -1DCh
            float track_distance;               // -1D8h
// .text:0048CF7A fAttackMotionRatio= dword ptr -1D4h
// .text:0048CF7A var_1D0         = dword ptr -1D0h
// .text:0048CF7A var_1C8         = dword ptr -1C8h
            AttackInfo[] Damages = new AttackInfo[4];/// .text:0048CF7A Damages         = StructCreature::_ATTACK_INFO ptr -1C4h
            string szScript;                    // -260   -104h
//.text:0048CF7A var_4           = dword ptr -4
//.text:0048CF7A pEnemy          = dword ptr  8
//.text:0048CF7A t               = dword ptr  0Ch
            int i;
            bool bInvincible;

// Data           :   ebp Relative, [FFFFFFB8], Local, Type: struct ArcadiaLock, __lock
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: unsigned int, ry2
// Data           :   ebp Relative, [FFFFFFE8], Local, Type: float, gap
// Data           :   ebp Relative, [FFFFFF7C], Local, Type: struct ArcadiaAutoLock, _lock
// Data           :   ebp Relative, [FFFFFFDC], Local, Type: float, enemy_distance
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: unsigned int, hSkillTarget
// Data           :   ebp Relative, [FFFFFFEC], Local, Type: float, track_distance
// Typedef        :   PATH, Type: class std::vector<X2D::Point<int>,std::allocator<X2D::Point<int> > >
// Data           :   ebp Relative, [FFFFFF40], Local, Type: struct X2D::Point<int>, ptEnd
// Data           :   ebp Relative, [FFFFFF30], Local, Type: class std::vector<X2D::Point<int>,std::allocator<X2D::Point<int> > >, vPath
// Data           :   ebp Relative, [FFFFFF50], Local, Type: struct X2D::Point<int>, ptStart
// Data           :   ebp Relative, [FFFFFFE4], Local, Type: float, fMod
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: int, nPrevStatus
// Data           :   ebp Relative, [FFFFFFBC], Local, Type: class std::_Vector_iterator<unsigned int,std::allocator<unsigned int> >, it
// Data           :   ebp Relative, [FFFFFFF0], Local, Type: float, fAttackMotionRatio



//             v3 = this;
//             v4 = &this->baseclass_0.baseclass_0.baseclass_0.mv;
//             v5 = pEnemya;
//             *&fAttackMotionRatio = GameContent.g_nRegionSize;
//             v102 = pEnemya;
//             v6 = this.mv.y;
//             LODWORD(rx1) = (uint)(this.mv.x / GameContent.g_nRegionSize);
//             LODWORD(ry1) = (this.mv.y / GameContent.g_nRegionSize);
//             v7 =  pEnemy.mv.x;
//             thisa = &pEnemya->baseclass_0.baseclass_0.mv;
//             v8 = (pEnemy.mv.y / GameContent.g_nRegionSize);
//             rx2 = (pEnemy.mv.x / GameContent.g_nRegionSize);

//             RappelzServer.Instance._LockArea((uint)(this.mv.x / GameContent.g_nRegionSize),
//                     (uint)(this.mv.y / GameContent.g_nRegionSize),
//                     (pEnemy.mv.x / GameContent.g_nRegionSize),
//                     (pEnemy.mv.y / GameContent.g_nRegionSize));
//             while ( 1 )
//             {
//                 *&fAttackMotionRatio = GameContent.g_nRegionSize;
//                 v10 = GameContent.g_nRegionSize;
//                 if ( LODWORD(rx1) == (*v4 / GameContent.g_nRegionSize) )
//                 {
//                     if ( LODWORD(ry1) == (v3->baseclass_0.baseclass_0.baseclass_0.mv.baseclass_0.y / GameContent.g_nRegionSize)
//                       && (pEnemy.mv.x / GameContent.g_nRegionSize) == (pEnemy.mv.x / GameContent.g_nRegionSize)
//                       && (pEnemy.mv.y / GameContent.g_nRegionSize) == (pEnemy.mv.y / GameContent.g_nRegionSize) )
//                         break;
//                 }
//                 *&szScript[240] = &__lock;
//                 v16 = ArcadiaServer::Instance();
//                 ArcadiaServer::UnLock(v16, *&szScript[240]);
//                 *&fAttackMotionRatio = GameContent.g_nRegionSize;
//                 v17 = v3->baseclass_0.baseclass_0.baseclass_0.mv.baseclass_0.y;
//                 LODWORD(rx1) = (*v4 / GameContent.g_nRegionSize);
//                 LODWORD(ry1) = (v17 / GameContent.g_nRegionSize);
//                 v18 = v5->baseclass_0.baseclass_0.mv.baseclass_0.y  / GameContent.g_nRegionSize;
//                 rx2 = (thisa->baseclass_0.x / GameContent.g_nRegionSize);
//                 *&szScript[240] = 255;
//                 *&szScript[236] = "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp";
//                 *&szScript[232] = v18;
//                 *&szScript[228] = rx2;
//                 nPrevStatus = v18;
//                 *&szScript[224] = (v17 / GameContent.g_nRegionSize);
//                 *&szScript[220] = LODWORD(rx1);
//                 *&szScript[216] = &result;
//                 v19 = ArcadiaServer::Instance();
//                 __lock.handle = ArcadiaServer::_LockArea(
//                                     v19,
//                                     *&szScript[216],
//                                     *&szScript[220],
//                                     *&szScript[224],
//                                     *&szScript[228],
//                                     *&szScript[232],
//                                     *&szScript[236],
//                                     *&szScript[240])->handle;
//             }
//             ArcadiaAutoLock::ArcadiaAutoLock(
//                 &_lock,
//                 &__lock,
//                 "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                 258);

//            v110 = 0;
            if (!this.bIsInWorld)
            {
//            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                return;
            }
            if ((this.IsNonAttacker() || this.IsAutoTrap() || this.IsAgent() && (!pEnemy.IsPlayer() || !(pEnemy as Player).m_bAutoUsed)
              && pEnemy.m_hEnemy != this.m_hHandle
              || GameContent.IsVisibleRegion((uint)(this.mv.x / GameContent.g_nRegionSize),
                        (uint)(this.mv.y / GameContent.g_nRegionSize),
                        (uint)(pEnemy.mv.x / GameContent.g_nRegionSize),
                        (uint)(pEnemy.mv.y / GameContent.g_nRegionSize)) == 0
              || pEnemy.m_layer != this.m_layer))
            {
                bInvincible = false;
                this.comeBackHome(bInvincible);
                //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                return;
            }

            enemyPosition = pEnemy.GetCurrentPosition(t);
            myPosition = this.GetCurrentPosition(t);
            ry1 = myPosition.GetDistance(enemyPosition);

///////////////////////
            if (this.GetNextAttackableTime() <= t)
            {
                i = 0;
                while (!this.CheckTriggerCondition(i))
                {
                    ++i;
                    if (i >= 6)
                        break;
                }
                if (i < 6)
                {
                    pos = this.GetCurrentPosition(t);
                    szScript = String.Format("{0}( {1}, {2}, {3}, {4}, {5}, {6}, {7} )", this.m_pContentInfo.trigger[i].script,
                        this.m_hHandle, pEnemy.m_hHandle, i, pos.x, pos.y, this.m_layer, this.m_bIsDungeonRaidMonster ? 1 : 0);

                    if (this.mv.bIsMoving)
                    {
                        if (this.bIsInWorld)
                        {
                            if (this.m_pContentInfo.trigger[i].script.Contains("trigger"))
                            {
                                stopPosition = this.GetCurrentPosition(t + 10);
                                RappelzServer.Instance.SetMove(this, myPosition, stopPosition, 0, true, Globals.GetArTime(), true);
                            }
                        }
                    }

                    this.m_bContinueAttack = false;

                    LuaVM.Instance.RunString(this, szScript);
                    if (!this.m_bContinueAttack)
                    {
                        //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                        return;
                    }
                    this.m_bContinueAttack = false;
                }

                // now see about casting skills
                //        LABEL_26:
                /*
                            v26 = 0;
                            while ( 1 )
                            {
                                if ( this.m_pContentInfo.skill_info[v26].skill_id != 0)
                                {
                                    if (this.m_pContentInfo.skill_info[v26].skill_probability != 0.0f)
                                    {
                                        if (this.m_pContentInfo.skill_info[v26].skill_probability * 10000.0 > Globals.GetRandomInt32(0, 10000))
                                        {
                                            nPrevStatus = this.m_hEnemy;
                                            v28 = this.GetSkill(this.m_pContentInfo.skill_info[v26].skill_id);
                                            if ( v28 )
                                            {
                                                if ( !v28->m_pSkillBase->is_harmful )
                                                    nPrevStatus = this.m_hHandle;
                                                if (this.mv.bIsMoving && this.bIsInWorld)
                                                {
                                                    newPos = this.GetCurrentPosition(t + 10);
                                                    RappelzServer.Instance.SetMove(this,myPosition,newPos,0,true, Globals.GetArTime(), true);
                                                }

                                                if (this.CastSkill(this.m_pContentInfo.skill_info[v26].skill_id,
                                                    this.m_pContentInfo.skill_info[v26].skill_lvl,
                                                    nPrevStatus, pEnemy.GetCurrentPosition(t), this.m_layer, false) != 0)
                                                    break;
                                            }
                                        }
                                    }
                                }
                                ++v26;
                                if ( v26 >= 6 )
                                {
                                    v15 = t;
                                    goto LABEL_39;
                                }
                            }
                */
            }

            LABEL_39:

            bInvincible = false;

            HateTag ht = this.getHateTag(pEnemy.m_hHandle,0);

            if (!this.m_bIsDungeonRaidMonster && ((ht != null && ht.nTime + 2500 < t) && pEnemy.mv.bIsMoving && pEnemy.bIsInWorld && ry1 > 360.0f 
               || 0.0f != this.m_nLastEnemyDistance && ry1 > 600.0f && this.m_nLastEnemyDistance < ry1))
            {
                HateTag ht2 = this.getHateTag(pEnemy.m_hHandle, t);

                if (ht2 != null)
                {
                    ht2.nBadAttackCount++;
                    ht2.bIsActive = false;
                    fMod = ((float)ht2.nHate * 0.5f);

                    if (fMod < 100)
                        fMod = 100;
                    ht2.nHate -= (int)fMod;
                }
                this.findNextEnemy();
                //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                return;
            }
            this.m_nLastEnemyDistance = ry1;

            rx1 = (pEnemy.GetUnitSize() * 0.5f) + (this.GetUnitSize() * 0.5f);
            if ((pEnemy.mv.IsMoving(t) && this.GetRealAttackRange() * 1.5f < ry1 - rx1)
              || (!pEnemy.mv.IsMoving(t) && this.GetRealAttackRange() * 1.2f < ry1 - rx1))
            {
                if (this.mv.bIsMoving && this.bIsInWorld && !pEnemy.mv.IsMoving(t)
                  && (this.GetRealAttackRange() * 1.2f >= this.mv.GetTargetPos().GetDistance(enemyPosition) - rx1)
                  || !this.IsActable()
                  || !this.IsMovable()
                  || this.m_nMovableTime > t)
                {
                    //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                    return;
                }


                targetPosition.x = enemyPosition.x;
                targetPosition.y = enemyPosition.y;
                targetPosition.z = enemyPosition.z;
                targetPosition.face = enemyPosition.face;
                if (!pEnemy.mv.bIsMoving || !pEnemy.bIsInWorld)
                {
                    this.findAttackablePosition(myPosition, targetPosition, ry1, this.GetRealAttackRange() + rx1);
                }
                else
                {
                    targetPosition = pEnemy.GetCurrentPosition(t + 15);
                }
                if ( GameRule.bMonsterPathFinding && !GameContent.IsBlocked(targetPosition.x, targetPosition.y))
                {
//                         this.m_pathFindPolygons.Clear();
//                         GameContent.GetCollisionPolygons(myPosition.x,myPosition.y,targetPosition.x,targetPosition.y,this.m_pathFindPolygons);
//                         vPath._Myfirst = 0;
//                         vPath._Mylast = 0;
//                         vPath._Myend = 0;
//                         LOBYTE(v110) = 1;
//                         end.baseclass_0._Myptr = myPosition.x;
//                         v87 = myPosition.y;
//                         track_distance = 0.0;
//                         ptEnd.baseclass_0.x = targetPosition.x;
//                         v51 = v3->m_pathFindPolygons._Mylast;
//                         ptEnd.baseclass_0.y = targetPosition.y;
//                         std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                             &v85,
//                             v51,
//                             &v3->m_pathFindPolygons.baseclass_0.___u0.baseclass_0);
//                         std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                             &v88,
//                             v3->m_pathFindPolygons._Myfirst,
//                             &v3->m_pathFindPolygons.baseclass_0.___u0.baseclass_0);
//                         X2D::PathFinder<int_X2D::Polygon<int>__>::_Find<std::_Vector_iterator<X2D::Polygon<int>___std::allocator<X2D::Polygon<int>__>>>(
//                             v88,
//                             __PAIR__(v85, begin.baseclass_0.baseclass_0.baseclass_0._Mycont),
//                             __PAIR__((&end + 4), end.baseclass_0.baseclass_0.baseclass_0._Mycont),
//                             &ptEnd,
//                             &vPath,
//                             &track_distance,
//                             *&szScript[244]);
//                         LOBYTE(v110) = 0;
//                         std::vector<GameContent::REGEN_INFO_std::allocator<GameContent::REGEN_INFO>>::_Tidy(&vPath);
                }
                this.SetStatus(MonsterStatus.Tracking);
                homePosition.x = this.m_RespawnX;
                homePosition.y = this.m_RespawnY;
                homePosition.z = 0.0f;
                track_distance = myPosition.GetDistance(homePosition);
                if (this.m_bIsDungeonRaidMonster || this.GetChaseRange() >= track_distance)
                {

                    if (this.m_nLastTrackTime + 50 < t)
                    {
                        this.m_nLastTrackTime = t;
                        track_distance = (((float)Globals.GetRandomInt32(0,9) / 100.0f) + 1.0f);
                        if ( !GameContent.IsBlocked(targetPosition.x, targetPosition.y) && this.IsMovable())
                        {
                            RappelzServer.Instance.SetMove(this, this.GetCurrentPosition(t), targetPosition, (sbyte)((this.GetMoveSpeed() / 7) * track_distance),true,
                                Globals.GetArTime(), true);
                        }
                    }
                    //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                    return;
                }
                bInvincible = true;
    LABEL_121:
                this.comeBackHome(bInvincible);
                //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                return;
            }
            if (this.GetStatus() == MonsterStatus.FindAttackPos && this.mv.IsMoving(t))
            {
                //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                return;
            }
            if ( !pEnemy.mv.IsMoving(t) && (this.GetStatus() == MonsterStatus.Tracking || pEnemy.m_vEnemyList.Count  < 6&& Globals.GetRandomInt32(0, 99) < 5))
            {
                RappelzServer.Instance.EnumMovableObject(myPosition, this.m_layer, this.GetUnitSize() * 0.5f, vList, true, true);

                foreach (uint m_id in vList)
                {
                    if (m_id != 1073741824 || m_id <= this.m_hHandle)
                    {
                        if (this.GetStatus() != MonsterStatus.Tracking)
                            continue;
                        if (!pEnemy.IsPlayer())
                            continue;

                        if (pEnemy.m_hHandle != m_id)
                            continue;
                    }
                    break;
                }

//                     for ( it = v95;
//                           ;
//                           std::_Vector_const_iterator<AutoAuctionInfo___std::allocator<AutoAuctionInfo__>>::operator__(&it) )
//                     {
//                         std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                             &begin.baseclass_0._Myptr,
//                             vList._Mylast,
//                             &vList.baseclass_0.___u0.baseclass_0);
//                         if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
//                                  &it,
//                                  &begin.baseclass_0._Myptr) )
//                         {
//                             LOBYTE(v110) = 0;
//                             std::vector<GameContent::REGEN_INFO_std::allocator<GameContent::REGEN_INFO>>::_Tidy(&vList);
//                             goto LABEL_95;
//                         }
//                         if ( (LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&it)->end.x) & 0xE0000000) != 1073741824
//                           || (LODWORD(track_distance) = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&it),
//                               track_distance <= this.m_hHandle)
//                         {
//                             if (this.GetStatus() != MonsterStatus.Tracking)
//                                 continue;
//                             if (!pEnemy.IsPlayer())
//                                 continue;
//                             track_distance = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(&it);
// 
//                             if (pEnemy.m_hHandle != track_distance)
//                                 continue;
//                         }
//                         break;
//                     }
                attack_pos = this.getNonDuplicateAttackPos(pEnemy);
                this.SetStatus(MonsterStatus.FindAttackPos);
                if (!GameContent.IsBlocked(attack_pos.x, attack_pos.y) && this.IsMovable())
                {
                    RappelzServer.Instance.SetMove(this,myPosition,attack_pos, (sbyte)(this.GetMoveSpeed() / 7),true,Globals.GetArTime(),true);
                }
                //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                return;
            }
    LABEL_95:
            nPrevStatus = (int)this.GetStatus();
            this.SetStatus(MonsterStatus.Attack);
            if (this.GetNextAttackableTime() > t)
            {
    LABEL_117:
                if (pEnemy.mv.IsMoving(t) && nPrevStatus == (int)MonsterStatus.Tracking)
                    this.SetStatus(MonsterStatus.Tracking);
                //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                return;
            }
            if (!this.IsAttackable() || !this.IsEnemy(pEnemy, false) || pEnemy.m_nHP == 0)
            {
                //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
                return;
            }
            if (this.mv.bIsMoving && this.bIsInWorld)
            {
                RappelzServer.Instance.SetMove(this,myPosition,this.GetCurrentPosition(t+10),0,true,Globals.GetArTime(),true);
            }

            for(i = 3; i >= 0; --i)
            {
                Damages[i] = new AttackInfo();
            }

            bDoubleAttack = false;
            this.Attack(pEnemy, t, this.GetAttackInterval(), Damages, ref bDoubleAttack);

            switch(this.m_pContentInfo.attack_speed_type)
            {
                case 1:
                    fMod = 0.6f;
                    break;

                case 2:
                    fMod = 0.7f;
                    break;

                case 3:
                    fMod = 1.0f;
                    break;

                default:
                    fMod = 0.5f;
                    break;
            }

            this.m_nMovableTime = (uint)((float)this.GetAttackInterval() * fMod + t);
            this.broadcastAttackMessage(pEnemy, Damages, (int)(10 * this.GetAttackInterval()),(int)(10 * (this.GetNextAttackableTime() - t)),
                bDoubleAttack, false, false, false);
            if (pEnemy.mv.IsMoving(t) && nPrevStatus == (int)MonsterStatus.Tracking)
                this.SetStatus(MonsterStatus.Tracking);
            //            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
//        LABEL_122:
//            ArcadiaAutoLock::_ArcadiaAutoLock(&_lock);
        
        }

        protected void AI_processAttack(uint t)
        {
// .text:0048DD50 _lock           = ArcadiaAutoLock ptr -68h
// .text:0048DD50 ry2             = dword ptr -28h
// .text:0048DD50 enemy_handle    = dword ptr -24h
// .text:0048DD50 __lock          = ArcadiaLock ptr -20h
// .text:0048DD50 rx1             = dword ptr -1Ch
// .text:0048DD50 ry1             = dword ptr -18h
// .text:0048DD50 rx2             = dword ptr -14h
// 
// Data           :   ebp Relative, [FFFFFFDC], Local, Type: unsigned int, enemy_handle
// Data           :   ebp Relative, [FFFFFF98], Local, Type: struct ArcadiaAutoLock, _lock
// Data           :   ebp Relative, [FFFFFFAC], Local, Type: struct ArcadiaAutoLock, _lock
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: struct ArcadiaLock, __lock
// Data           :   ebp Relative, [FFFFFFD8], Local, Type: unsigned int, ry2
// Data           :   ebp Relative, [FFFFFFEC], Local, Type: unsigned int, rx2
// Data           :   ebp Relative, [FFFFFFC0], Local, Type: struct ArcadiaAutoLock, _lock
// Data           :   ebp Relative, [FFFFFFE4], Local, Type: unsigned int, rx1
// Data           :   ebp Relative, [FFFFFFE8], Local, Type: unsigned int, ry1


            RLock rl1 = RappelzServer.Instance._LockObjectWithVisibleRange(this);
            AutoLock al1 = new AutoLock(rl1.handle);

            //ArcadiaAutoLock::_ArcadiaAutoLock((v2 - 104));
            if (this.m_pCastSkill != null)
            {
                this.m_pCastSkill.ProcSkill();
                return;
            }

            Creature target = GameObject.raw_get(this.m_hEnemy) as Creature;

            rl1 = RappelzServer.Instance._LockObjectWithVisibleRange(this);
            al1 = new AutoLock(rl1.handle);

            if (target == null 
              || target.m_hHandle != this.m_hEnemy
              || target.m_nHP == 0
              || !target.bIsInWorld
              || !this.IsVisible(target)
              || target.IsPlayer() && (target as Player).IsInBattleField()
              || target.IsSummon() && (target as Summon).m_master.IsInBattleField())
            {
                this.removeFromHateList(this.m_hEnemy);
                this.findNextEnemy();
            }
            else
            {
//                ArcadiaAutoLock::_ArcadiaAutoLock((v2 - 84));
//                 *(v2 - 16) = g_nRegionSize;
//                 v12 = *(v2 - 16);
//                 v13 = this.mv.baseclass_0.y;
//                 *(v2 - 28) = (this.mv.baseclass_0.x / *(v2 - 16));
//                 v14 = (v13 / v12);
//                 v15 = v9->baseclass_0.mv.baseclass_0.x;
//                 *(v2 - 24) = v14;
//                 v16 = (v15 / v12);
//                 v17 = v9->baseclass_0.mv.baseclass_0.y / v12;
//                 *(v2 - 20) = v16;
//                 v18 = *(v2 - 20);
//                 *(v2 - 40) = v17;
//                 v19 = *(v2 - 24);
//                 v20 = *(v2 - 28);
//                 v21 = ArcadiaServer::Instance();
//                 ArcadiaServer::_LockArea(
//                     v21,
//                     (v2 - 32),
//                     v20,
//                     v19,
//                     v18,
//                     v17,
//                     "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                     689);
//                 while ( 1 )
//                 {
//                     *(v2 - 16) = g_nRegionSize;
//                     v22 = *(v2 - 16);
//                     if ( *(v2 - 28) == (this.mv.baseclass_0.x / *(v2 - 16)) )
//                     {
//                         if ( *(v2 - 24) == (this.mv.baseclass_0.y / v22)
//                           && *(v2 - 20) == (v9->baseclass_0.mv.baseclass_0.x / v22)
//                           && *(v2 - 40) == (v9->baseclass_0.mv.baseclass_0.y / v22) )
//                             break;
//                     }
//                     v25 = ArcadiaServer::Instance();
//                     ArcadiaServer::UnLock(v25, (v2 - 32));
//                     *(v2 - 16) = g_nRegionSize;
//                     v26 = *(v2 - 16);
//                     v27 = this.mv.baseclass_0.y;
//                     *(v2 - 28) = (this.mv.baseclass_0.x / *(v2 - 16));
//                     v28 = (v27 / v26);
//                     v29 = v9->baseclass_0.mv.baseclass_0.x;
//                     *(v2 - 24) = v28;
//                     v30 = (v29 / v26);
//                     v31 = v9->baseclass_0.mv.baseclass_0.y / v26;
//                     *(v2 - 20) = v30;
//                     v32 = *(v2 - 20);
//                     *(v2 - 40) = v31;
//                     v33 = *(v2 - 24);
//                     v34 = *(v2 - 28);
//                     v35 = ArcadiaServer::Instance();
//                     *(v2 - 32) = ArcadiaServer::_LockArea(
//                                      v35,
//                                      (v2 - 44),
//                                      v34,
//                                      v33,
//                                      v32,
//                                      v31,
//                                      "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                                      701)->handle;
//                 }
//                ArcadiaAutoLock::ArcadiaAutoLock((v2 - 32));

                if ((this.m_StatusFlag & StatusFlags.FirsAttack) != 0)
                {
                    target.OnUpdate();
                    this.m_StatusFlag &= ~StatusFlags.FirsAttack;
                }
                if (target.m_nHP != 0)
                {
//                    ArcadiaAutoLock::_ArcadiaAutoLock((v2 - 64));
                    this.AI_processAttack(target, t);
                    return;
                }
                this.removeFromHateList(this.m_hEnemy);
                this.findNextEnemy();
            }

//            ArcadiaAutoLock::_ArcadiaAutoLock(v24);

        }

        protected void processWalk(uint t)
        {
//text:0048AE95 tmp_mv          = ArMoveVector ptr -84h
// .text:0048AE95 _lock           = ArcadiaAutoLock ptr -44h
// .text:0048AE95 __lock          = ArcadiaLock ptr -18h
// .text:0048AE95 ry              = dword ptr -14h
// .text:0048AE95 t               = dword ptr  8
            int wpi = 0;
            ArMoveVector tmp_mv;
//             *(v2 - 4) = 0;
//             v4 = ArcadiaServer::Instance();
//             v5 = ArcadiaServer::_LockObjectWithVisibleRange(
//                      v4,
//                      (v2 - 20),
//                      &v3->baseclass_0.baseclass_0.baseclass_0,
//                      "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                      955);
//             ArcadiaAutoLock::ArcadiaAutoLock(
//                 (v2 - 68),
//                 v5,
//                 "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                 955);

            tmp_mv = new ArMoveVector(this.mv);
//            ArcadiaAutoLock::_ArcadiaAutoLock((v2 - 68));
            tmp_mv.Step(t);
            if (this.GetStatus() == MonsterStatus.Normal)
            {
                if (!this.m_bComeBackHome)
                {
                    if (this.m_pWayPointInfo != null)
                    {
                        this.m_RespawnX = tmp_mv.x;
                        this.m_RespawnY = tmp_mv.y;
                        if (this.m_nWayPointIdx < 0 && this.m_pWayPointInfo.way_point_type == 1 )
                        {
                            wpi = -tmp_mv.ends.Count;
                        }
                        else
                        {
                            wpi = this.m_pWayPointInfo.vWayPoint.Count - tmp_mv.ends.Count - 1;
                        }
                        this.m_nWayPointIdx = wpi;
                    }
                }
            }
//             *(v2 - 16) = GameContent.g_nRegionSize;
//             v9 = GameContent.g_nRegionSize;
//             v10 = tmp_mv.x;
//             *(v2 - 24) = (this.mv.x / GameContent.g_nRegionSize);
//             v11 = (tmp_mv.x / GameContent.g_nRegionSize);
//             v27 = v11 == (this.mv.x / GameContent.g_nRegionSize);
//             *(v2 - 16) = v11;
            if ((tmp_mv.x / GameContent.g_nRegionSize) != (this.mv.x / GameContent.g_nRegionSize) || (tmp_mv.y / GameContent.g_nRegionSize) != (this.mv.y / GameContent.g_nRegionSize) || !tmp_mv.bIsMoving)
            {
//                 v12 = (this.mv.x / GameContent.g_nRegionSize);
//                 v13 = (this.mv.y / GameContent.g_nRegionSize);
//                 v14 = (tmp_mv.y / GameContent.g_nRegionSize);
//                 *(v2 - 20) = v13;
//                 v15 = *(v2 - 16);
//                 v16 = *(v2 - 20);

//                 RappelzServer.Instance._LockArea((this.mv.x / GameContent.g_nRegionSize),
//                     v12,
//                     v16,
//                     v15,
//                     v14,
//                     "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                     984);
//                 while ( 1 )
//                 {
//                     *(v2 - 16) = GameContent.g_nRegionSize;
//                     if ( v12 == (this.mv.x / GameContent.g_nRegionSize))
//                     {
//                         if ( *(v2 - 20) == (this.mv.y / GameContent.g_nRegionSize))
//                             break;
//                     }
//                     ArcadiaServer::UnLock((v2 - 24));
//                     *(v2 - 16) = g_nRegionSize;
//                     v19 = *(v2 - 16);
//                     v12 = (this.mv.x / GameContent.g_nRegionSize);
//                     v20 = *(v2 - 128);
//                     *(v2 - 20) = (this.mv.y / GameContent.g_nRegionSize);
//                     v21 = (v20 / v19);
//                     v22 = *(v2 - 132) / v19;
//                     *(v2 - 16) = v21;
//                     v23 = *(v2 - 16);
//                     v24 = *(v2 - 20);
//                     *(v2 - 24) = ArcadiaServer::_LockArea(
//                                      (v2 - 28),
//                                      v12,
//                                      v24,
//                                      v22,
//                                      v23,
//                                      "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                                      994)->handle;
//                 }
//                 ArcadiaAutoLock::ArcadiaAutoLock(
//                     (v2 - 48),
//                     (v2 - 24),
//                     "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                     997);

                if (!this.bIsInWorld)
                {
                    return;
                }

                if (this.m_bComeBackHome && !this.IsBattleMode())
                {
                    if (tmp_mv.bIsMoving)
                    {
//        LABEL_24:

                        RappelzServer.Instance.onRegionChange(this, t - this.lastStepTime, !tmp_mv.bIsMoving);
//        LABEL_25:
//                        ArcadiaAutoLock::_ArcadiaAutoLock((v2 - 48));
                        return;
                    }
                    if ((this.m_StatusFlag & StatusFlags.Invincible) != 0)
                        this.m_StatusFlag &= ~StatusFlags.Invincible;
                    this.m_bComeBackHome = false;
                }
                RappelzServer.Instance.onRegionChange(this, t - this.lastStepTime, !tmp_mv.bIsMoving);
//                ArcadiaAutoLock::_ArcadiaAutoLock((v2 - 48));
            }
        }

        protected void processMove(uint t)
        {
//_lock           = ArcadiaAutoLock ptr -54h
// .text:0048B509 vMoveInfo       = std::vector<ArPosition,std::allocator<ArPosition> > ptr -30h
// .text:0048B509 targetPos       = ArPosition ptr -20h
// .text:0048B509 t               = dword ptr  4
// .text:0048B509 speed           = byte ptr  8
            List<ArPosition> vMoveInfo = new List<ArPosition>();
            ArPosition targetPos = new ArPosition();

            byte speed;

            if (!this.IsDungeonConnector())
            {
//                 v5 = RappelzServer.Instance._LockObjectWithVisibleRange(
//                          v4,
//                          (v2 - 16),
//                          &v3->baseclass_0.baseclass_0.baseclass_0,
//                          "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                          1149);
//                 ArcadiaAutoLock::ArcadiaAutoLock(
//                     (v2 - 84),
//                     v5,
//                     "D:\\alienbrainWork\\Source Code\\@Rappelz\\Server\\GameServer_For_Update\\090721_GameServer\\Game\\NPCProc\\MonsterAI.cpp",
//                     1149);

                if (this.m_nHP != 0)
                {
                    if (this.m_pWayPointInfo != null)
                    {
                        if (!this.mv.bIsMoving || !this.bIsInWorld )
                        {
                            int lwpi = this.m_pWayPointInfo.vWayPoint.Count-1;
                            if (this.m_nWayPointIdx >= lwpi)
                            {
                                if (this.m_pWayPointInfo.way_point_type == 1 )
                                    this.m_nWayPointIdx = -lwpi;
                                else
                                    this.m_nWayPointIdx = -1;
                            }

                            if (this.m_pWayPointInfo.way_point_type == 1 && this.m_nWayPointIdx < 0 )
                                lwpi = 0;
                            int wpi = this.m_nWayPointIdx;

                            while (true)
                            {
                                ++wpi;
                                if (wpi > lwpi)
                                    break;
                                int awpi = Math.Abs(wpi);
                                targetPos = this.m_pWayPointInfo.vWayPoint[awpi];
                                vMoveInfo.Add(targetPos);
                            }
                            t = Globals.GetArTime();
                            speed = (byte)(this.m_pWayPointInfo.way_point_speed / 7);
//                            v15 = this.m_pWayPointInfo.way_point_speed % 7;

                            if (speed == 0)
                                speed = (byte)(this.GetMoveSpeed() / 7);

                            RappelzServer.Instance.SetMultipleMove(this, this.GetCurrentPosition(t),vMoveInfo, (sbyte)speed, true, t, true);
                        }
                    }
                    else
                    {
                        if (this.GetStatus() != MonsterStatus.Normal || this.bIsNearClient || this.m_vHateList.Count > 0)
                        {
                            if (this.m_bIsWandering )
                            {
                                if (GameRule.bMonsterWandering)
                                {
                                    int rnd = Globals.GetRandomInt32();
                                    if (this.GetStatus() == MonsterStatus.Normal)
                                    {
                                        if (this.m_nHP != 0 && (!this.mv.bIsMoving || !this.bIsInWorld))
                                        {
                                            if (rnd % 500 + this.lastStepTime + 200 < t)
                                            {
                                                if ((rnd % 3) != 0)
                                                {
                                                    this.getMovePosition(targetPos);
                                                    if (!GameContent.IsBlocked(targetPos.x, targetPos.y))
                                                    {
                                                        speed = (byte)(this.GetMoveSpeed() / 7);
                                                        t = Globals.GetArTime();
                                                        RappelzServer.Instance.SetMove(this, this.GetCurrentPosition(t),targetPos, (sbyte)speed, true, t, true);
                                                        this.m_RespawnX = targetPos.x;
                                                        this.m_RespawnY = targetPos.y;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            GameContent.ClearTamer(this,true);
                            this.SetStatus(0);
                            RappelzServer.Instance.SetObjectPriority(this, SchedulerObject.Priority.Idle);
                        }
                    }
                }
//                ArcadiaAutoLock::_ArcadiaAutoLock((v2 - 84));
            }

        }

        protected void processDead(uint t)
        {
            if (this.m_pDeleteHandler != null)
            {
                this.m_pDeleteHandler.onMonsterDelete(this);
            }

            RLock rl = RappelzServer.Instance._LockObjectWithVisibleRange(this);
            AutoLock al = new AutoLock(rl.handle);
            RappelzServer.Instance.SetObjectPriority(this, SchedulerObject.Priority.Normal);
            if (this.m_nDeadTime + 1200 < t && this.m_bIsEnable)
            {
                this.m_bIsEnable = false;
                if (this.bIsInWorld)
                    GameContent.RemoveMonsterFromWorld(this);
                RappelzServer.Instance.DeleteObject(this);
            }
//            ArcadiaAutoLock::_ArcadiaAutoLock((v2 - 36));

        }

        protected void processFirstAttack(uint t)
        {
// .text:0048B138 _lock           = ArcadiaAutoLock ptr -80h
        List<Monster> vSameGroup = new List<Monster>();// .text:0048B138 vSameGroup      = std::vector<StructMonster *,std::allocator<StructMonster *> > ptr -5Ch
        List<uint> vResult = new List<uint>();// .text:0048B138 vResult         = std::vector<unsigned int,std::allocator<unsigned int> > ptr -3Ch
// .text:0048B138 it              = std::_Vector_iterator<StructMonster *,std::allocator<StructMonster *> > ptr -24h
            float distance;//        = dword ptr -18h
            float _distance;//       = dword ptr -14h
            uint target;//          = dword ptr -10h
// .text:0048B138 t               = dword ptr  8
// 
// 
// Data           :   ebp Relative, [FFFFFF80], Local, Type: struct ArcadiaAutoLock, _lock
// Data           :   ebp Relative, [FFFFFFA4], Local, Type: class std::vector<StructMonster *,std::allocator<StructMonster *> >, vSameGroup
// Data           :   ebp Relative, [FFFFFFC4], Local, Type: class std::vector<unsigned int,std::allocator<unsigned int> >, vResult
// Data           :   ebp Relative, [FFFFFFB4], Local, Type: class std::vector<unsigned int,std::allocator<unsigned int> >, vResult
// Data           :   ebp Relative, [FFFFFFE8], Local, Type: float, distance
// Data           :   ebp Relative, [FFFFFFEC], Local, Type: float, _distance



            RLock rl1 = RappelzServer.Instance._LockObjectWithVisibleRange(this);
            AutoLock al1 = new AutoLock(rl1.handle);

            
            if (this.GetStatus() != MonsterStatus.Dead
              && (this.m_nRegenTime + 1000 <= t || this.m_bRespawnByScript)
              && this.GetStatus() == MonsterStatus.Normal
              && (this.IsAgent() || this.IsFirstAttacker() || this.IsBattleRevenger()) )
            {
                target = 0;

                if (this.IsAgent())
                {
                    RappelzServer.Instance.EnumMovableObject(this.mv, this.m_layer, this.GetFirstAttackRange(),vResult,true,true);

                    foreach (uint handle1 in vResult)
                    {
                        Player p = GameObject.raw_get(handle1) as Player;

                        if (p != null && p.m_nHP != 0 && p.m_bAutoUsed)
                        {
                            p.AddState(State.StateType.Normal, State.StateCode.NemesisForAuto,0,10,t,t + 8640000, false, 0, "");
                            target = p.m_hHandle;
                            break;
                        }
                    }
                }
                else
                {
                    RappelzServer.Instance.EnumMovableObject(this.mv,this.m_layer,this.GetFirstAttackRange(),vResult,true,true);

                    distance = this.GetFirstAttackRange() + 1.0f;

                    foreach(uint handle2 in vResult)
                    {
                        Creature cr = GameObject.raw_get(handle2) as Creature;

                        if (cr != null && cr.m_nHP != 0)
                        {
                            if ( !this.IsFirstAttacker() )
                            {
                                if (cr.IsMonster())
                                {
                                    if (cr.m_hEnemy != 0)
                                        target = cr.m_hEnemy;
                                }
                            }
                            if (this.IsGroupFirstAttacker() && cr.IsMonster() && !ReferenceEquals(cr,this))
                            {
                                Monster mob = cr as Monster;
                                if (mob.GetMonsterGroup() == this.GetMonsterGroup() )
                                {
                                    vSameGroup.Add(mob);
                                }
                            }
                            if (this.IsFirstAttacker())
                            {
                                if (this.IsEnemy(cr, false))
                                {
                                    _distance = this.mv.GetDistance(cr.GetCurrentPosition(t));
                                    if (!cr.IsSummon() || this.GetFirstAttackRange() * 0.5f >= _distance)
                                    {
                                        if (distance > _distance)
                                        {
                                            distance = _distance;
                                            target = handle2;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if (target != 0)
                {
                    if (this.IsFirstAttacker())
                    {
                        this.AddHate(target, 1, false, true);
                        if (this.IsGroupFirstAttacker())
                        {
                            foreach (Monster m in vSameGroup)
                            {
                                m.AddHate(target,1,false,true);
                            }
                        }
                    }
                    else
                    {
                        this.AddHate(target, 1, true, true);
                    }
                }
            }

//            ArcadiaAutoLock::_ArcadiaAutoLock((v2 - 128));

        }

        protected void findAttackablePosition(ArPosition myPosition, ArPosition enemyPosition, float distance, float gap)
        {
            ArPosition duplicateEnemyPosition;
            float walk_length;
            float v;

            duplicateEnemyPosition = new ArPosition(enemyPosition);

            walk_length = distance - gap;

            if (walk_length >= 0.0f)
            {
                v = (walk_length / distance) + 0.1f;
                enemyPosition.x = ((enemyPosition.x - myPosition.x) * v) + myPosition.x;
                enemyPosition.y = ((enemyPosition.y - myPosition.y) * v) + myPosition.y;
                enemyPosition.z = ((enemyPosition.z - myPosition.z) * v) + myPosition.z;

                if (!GameContent.IsBlocked(enemyPosition.x, enemyPosition.y))
                    return;

                enemyPosition.Copy(duplicateEnemyPosition);
            }
            else
            {
                enemyPosition.Copy(myPosition);
            }
        }


        protected void findNextEnemy()
        {
            Creature ct;
            uint target;                        // -24  -18h
            int nMaxHate;                       // -20  -14h
            int nHate;                          // -16  -10h

            nMaxHate = -1;
            target = 0;

            foreach (HateTag ht in this.m_vHateList)
            {
                if (ht.bIsActive)
                {
                    nHate = ht.nHate;

                    foreach (HateModifierTag hmt in this.m_vHateModifierByState)
                    {
                        if(hmt.uid == ht.uid)
                        {
                            nHate += hmt.nHate;
                            break;
                        }
                    }

                    if (nHate > nMaxHate)
                    {
                        ct = Creature.get(ht.uid) as Creature;
                        if (ct != null)
                        {
                            if (GameContent.IsVisibleRegion((uint)(ct.mv.x / (float)GameContent.g_nRegionSize), (uint)(ct.mv.y / (float)GameContent.g_nRegionSize),
                                (uint)(this.mv.x / (float)GameContent.g_nRegionSize), (uint)(this.mv.y / (float)GameContent.g_nRegionSize)) != 0)
                            {
                                if (this.IsVisible(ct))
                                {
                                    nMaxHate = nHate;
                                    target = ht.uid;
                                }
                            }
                        }
                    }
                }
            }

            if (nMaxHate == -1)
            {
                this.comeBackHome(false);
            }
            else
            {
                this.m_nMaxHate = nMaxHate;
                this.m_hEnemy = target;
                this.m_StatusFlag |= StatusFlags.FirsAttack;
            }

        }

        protected void getMovePosition(ArPosition newPos)
        {
            newPos.x = (Globals.GetRandomUInt32() % 120) + this.mv.x - 60.0f;
            newPos.y = (Globals.GetRandomUInt32() % 120) + this.mv.y - 60.0f;

            if (GameContent.g_nMapWidth < newPos.x)
                newPos.x = GameContent.g_nMapWidth;

            if (GameContent.g_nMapHeight < newPos.y)
                newPos.y = GameContent.g_nMapHeight;
            if (newPos.x < 0.0f)
                newPos.x = 0.0f;
            if (newPos.y < 0.0f)
                newPos.y = 0.0f;
        }

        protected ArPosition getNonDuplicateAttackPos(Creature pEnemy)
        {
//             StructCreature *v3; // edi@1
//             ArPosition *v4; // esi@1
//             unsigned int v5; // ebx@1
//             double v6; // st7@2
//             ArPosition *v7; // eax@8
//             ArPosition myPosition; // [sp+10h] [bp-1Ch]@4
//             double v9; // [sp+20h] [bp-Ch]@1
//             float distance; // [sp+28h] [bp-4h]@4
//             float angle; // [sp+34h] [bp+8h]@4
//             float anglea; // [sp+34h] [bp+8h]@8
//             float fMod; // [sp+38h] [bp+Ch]@1
//             float fModb; // [sp+38h] [bp+Ch]@4
//             float fModa; // [sp+38h] [bp+Ch]@4
//             float fModc; // [sp+38h] [bp+Ch]@5
//             float fModd; // [sp+38h] [bp+Ch]@5
//             float fMode; // [sp+38h] [bp+Ch]@8
//             float fModf; // [sp+38h] [bp+Ch]@8

            float range;
            float dist;
            float angle;
            ArPosition myPosition;
            float distance;
            float fMod;


            uint ct = Globals.GetArTime();
            ArPosition result = pEnemy.GetCurrentPosition(ct);

            range = this.GetRealAttackRange() + (this.GetUnitSize() * 0.5f) + (pEnemy.GetUnitSize() * 0.5f);
            fMod = Globals.GetRandomInt32(-1, 3);
            if (0.0 == fMod )
                fMod = 1.0f;

            angle = fMod * 0.6283f;
            myPosition = this.GetCurrentPosition(ct);
            distance = myPosition.GetDistance(result);
            fMod = 0.0f;
            if (distance != 0.0f)
            {
                fMod = (float)Math.Acos((myPosition.x - result.x) / distance);
            }
            if ( myPosition.y - result.y < 0.0f)
                fMod = 6.283f - fMod;
            angle = fMod + angle;
            fMod = (float)Math.Cos(angle);
            result.x = fMod * range + result.x;
            fMod = (float)Math.Sin(angle);
            result.y = fMod * range + result.y;
            return result;

        }

        protected HateTag getHateTag(uint handle, uint t)
        {
            foreach (HateTag ht in this.m_vHateList)
            {
                if(ht.uid == handle)
                {
                    ht.nTime = t;
                    return ht;
                }
            }
            return null;
        }


        protected HateTag addHate(uint handle, int nHate)
        {
            HateTag ht; // ebx@1

// Data           :   ebp Relative, [FFFFFFF0], Local, Type: unsigned long, t
// Data           :   ebp Relative, [FFFFFFEC], Local, Type: class XScopedLock, __scoped_lock
// Data           :   ebp Relative, [FFFFFFE4], Local, Type: struct StructCreature::iterator, it
// Data           :   ebp Relative, [FFFFFFE4], Local, Type: struct StructCreature::iterator, it

            Creature target;
            int lvl;
            uint tm;

            uint ct = Globals.GetArTime();
            ht = this.getHateTag(handle, ct);

            if (ht == null)
            {
                lock(this.m_vHateList)
                {
                    ht = new HateTag(handle, ct, nHate);
                    ht.bIsActive = true;
                    this.m_vHateList.Add(ht);

                    target = Creature.get(handle) as Creature;
                    target.AddToEnemyList(this.m_hHandle);
                }
            }

            ht.nHate += nHate;
            if (ht.nHate < 0)
                ht.nHate = 0;

            ht.nLastMaxHate = ht.nHate;
            if (!ht.bIsActive)
            {
                ht.bIsActive = true;

                if (ht.nBadAttackCount == 1)
                {
                    lvl = 1;
                    tm = ct + 300;
                }
                else
                {
                    lvl = 2;
                    tm = ct + 500;
                }

                this.AddState(State.StateType.Normal, State.StateCode.Frenzy, this.m_hHandle, lvl, ct, tm, false, 0, "");
            }

            if (this.m_hEnemy != 0)
            {
                if (this.m_hEnemy != handle)
                {
                    if (ht.nHate > this.m_nMaxHate)
                    {
                        this.m_nMaxHate = ht.nHate;
                        this.m_hEnemy = handle;
                        return ht;
                    }
                    if (this.m_hEnemy != handle)
                        return ht;
                }
                this.m_nMaxHate = ht.nHate;
                return ht;
            }

            this.m_nMaxHate = ht.nHate;

            if (Creature.get(handle) != null)
                this.StartAttack(handle, false);
            return ht;
        }

        protected bool removeFromHateList(uint handle)
        {
            bool found = false;
            lock(this.m_vHateList)
            {
                for(int i = this.m_vHateList.Count-1; i >= 0;--i)
                {
                    HateTag ht = this.m_vHateList[i];
                    if (ht.uid == handle)
                    {
                        this.m_vHateList.RemoveAt(i);
                        Creature cr = Creature.get(handle) as Creature;
                        if (cr != null)
                        {
                            found = true;
                            cr.RemoveFromEnemyList(this.m_hHandle);
                        }
                        break;
                    }
                }
            }
            return found;
        }

        protected void clearHateList()
        {

        }

        protected void updateHate()
        {

        }

        protected DamageTag getDamageTag(uint handle, uint t)
        {
            for(int i = this.m_vDamageList.Count-1; i >= 0; --i)
            {
                DamageTag dt = this.m_vDamageList[i];
                if (dt.uid  == handle)
                {
                    if(t != 0)
                        dt.nTime = t;
                    return dt;
                }
                if (dt.nTime + 30000 < t)
                {
                    this.m_nTotalDamage -= dt.nDamage;
                    this.m_vDamageList.RemoveAt(i);
                }
            }
            return null;
        }


        protected DamageTag addDamage(uint handle, int nDamage)
        {
            uint ct = Globals.GetArTime();

            DamageTag tag = this.getDamageTag(handle, ct);
            if (tag == null)
            {
                tag = new DamageTag(handle, ct, nDamage);
                m_vDamageList.Add(tag);
            }
            this.m_nTotalDamage += nDamage;
            tag.nDamage += nDamage;
            return tag;
        }

// Function       :   protected bool removeFromDamageList(unsigned int)

        protected void procDropChaos(Creature pKiller, takePriority pPriority, List<VirtualParty> vPartyContribute, float fDropRatePenalty, float fPCBangDropRateBonus)
        {
// .text:00447BE7 it              = std._Vector_iterator<_HATE_TAG> ptr -52 -34h
// .text:00447BE7 pit             = StructCreature.iterator ptr -44    -2Ch
// .text:00447BE7 itVector        = std._Vector_iterator<StructMonster> ptr -36    -24h
// Data           :   ebp Relative, [00000014], Param, Type: float, fPCBangDropRateBonus
// .text:00447BE7 pKiller         = dword ptr  4    04h
// .text:00447BE7 vPartyContribute= dword ptr  12   0Ch

            float fCurrentPlayerPenalty;            // -60  -3Ch
            float fGameTimeLimitPenalty;            // -28  -1Ch
            int nTaxRate;                           // -20  -14h
            int dungeon_tax;                        // 8    08h
            float chaos;                            // 16   10h
            float fSharedChaos;                     // 20   14h
            int nGuildID;                           // 20   14h

            Player p = null;



            float fChance = this.m_pContentInfo.chaos_drop_percentage * GameRule.fChaosDropRate * fDropRatePenalty * fPCBangDropRateBonus;
            int rnd = Globals.GetRandomInt32();
            chaos = rnd % 100;

            if (chaos >= fChance)
                return;

            fGameTimeLimitPenalty = 0;
            foreach (HateTag ht in this.m_vHateList)
            {
                if (ht.uid != 0)
                {
                    Creature cr = Creature.get(ht.uid) as Creature;
                    if (cr != null)
                    {
                        p = null;
                        if (cr.IsPlayer())
                            p = cr as Player;
                        else if(cr.IsSummon())
                            p = (cr as Summon).m_master;
                        if (p != null)
                        {
                            if (p.IsLoginComplete()
                                && p.m_nLogoutTime == 0
                                && p.bIsInWorld)
                            {
                                if (!p.IsGameTimeLimited())
                                {
                                    fGameTimeLimitPenalty = 1.0f;
                                    break;
                                }
                                else 
                                {
                                    float r = GameRule.GetGameTimeLimitPenalty(p.GetContinuousPlayTime());
                                    if (fGameTimeLimitPenalty < r)
                                        fGameTimeLimitPenalty = r;
                                }
                            }
                        }
                    }
                }
            }
            if (fGameTimeLimitPenalty == 0)
            {
                if (pKiller != null)
                {
                    p = null;
                    if (pKiller.IsPlayer())
                        p = pKiller as Player;
                    else if(pKiller.IsSummon())
                        p = (pKiller as Summon).m_master;

                    if (p != null)
                    {
                        if (p.IsLoginComplete())
                        {
                            if (p.m_nLogoutTime == 0)
                            {
                                if (p.bIsInWorld)
                                {
                                    if (p.IsGameTimeLimited())
                                    {
                                        float r = GameRule.GetGameTimeLimitPenalty(p.GetContinuousPlayTime());
                                        if (fGameTimeLimitPenalty < r)
                                            fGameTimeLimitPenalty = r;
                                    }
                                    else
                                    {
                                        fGameTimeLimitPenalty = 1.0f;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (fGameTimeLimitPenalty != 0)
            {
                chaos = (fGameTimeLimitPenalty * Globals.GetRandomInt32(this.m_pContentInfo.chaos_min, this.m_pContentInfo.chaos_max));
                if (this.m_nDungeonId != 0)
                {
                    DungeonManager.Instance.GetTaxRate(this.m_nDungeonId, out nTaxRate, out nGuildID);
                    dungeon_tax = (int)(nTaxRate * chaos / 100);
                    if (nGuildID != 0)
                    {
                        GuildManager.Instance.GiveTax(nGuildID, 0, dungeon_tax);
                    }
                    chaos -= dungeon_tax;
                }

                foreach (VirtualParty vp in vPartyContribute)
                {
                    fSharedChaos = vp.fContribute * chaos;

                    if (vp.hPlayer == 0)
                    {
                        GameContent.addChaos(this,vp.nPartyID, fSharedChaos);
                    }
                    else
                    {
                        p = Player.get(vp.hPlayer) as Player;
                        if (p != null)
                        {
                            GameContent.addChaos(this, p, fSharedChaos);
                        }
                    }
                }
            }

        }

        protected void procDropGold(ArPosition pos, Creature pKiller, takePriority pPriority, List<VirtualParty> vPartyContribute, float fDropRatePenalty, float fPCBangDropRateBonus)
        {
// .text:004453C2 fCurrentPlayerPenalty= c_fixed<10000> ptr -40h
// .text:004453C2 dungeon_tax     = StructGold ptr -38h
// .text:004453C2 it              = qword ptr -30h
            long gold;// .text:004453C2 gold            = StructGold ptr -20h
            int tax;
// .text:004453C2 fGameTimeLimitPenalty= c_fixed<10000> ptr -18h
// .text:004453C2 pos             = dword ptr  8
// .text:004453C2 pKiller         = dword ptr  0Ch
// .text:004453C2 pPriority       = dword ptr  10h
// .text:004453C2 vPartyContribute= dword ptr  14h
            int nGuildID;//        = dword ptr  18h
// .text:004453C2 nTaxRate        = dword ptr  1Ch
// 
// Data           :   ebp Relative, [00000018], Local, Type: float, fGoldDropRate
// Data           :   ebp Relative, [FFFFFFE8], Local, Type: class c_fixed<10000>, fGameTimeLimitPenalty
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: struct StructGold, gold
// Data           :   ebp Relative, [00000018], Local, Type: int, nEventItemCode
// Data           :   ebp Relative, [0000001C], Local, Type: const unsigned int, nEventItemFlag
// Data           :   ebp Relative, [FFFFFFD0], Local, Type: class std::_Vector_iterator<_HATE_TAG,std::allocator<_HATE_TAG> >, it
// Data           :   ebp Relative, [FFFFFFD8], Local, Type: struct StructCreature::iterator, pit
// Data           :   ebp Relative, [FFFFFFC0], Local, Type: class c_fixed<10000>, fCurrentPlayerPenalty
// Data           :   ebp Relative, [FFFFFFB0], Local, Type: class c_fixed<10000>, fCurrentPlayerPenalty
// Data           :   ebp Relative, [0000001C], Local, Type: int, nTaxRate
// Data           :   ebp Relative, [FFFFFFC8], Local, Type: struct StructGold, dungeon_tax
// Data           :   ebp Relative, [00000018], Local, Type: int, nGuildID
// Data           :   ebp Relative, [00000008], Param, Type: const struct ArPosition &, pos
// Data           :   ebp Relative, [0000000C], Param, Type: struct StructCreature *, pKiller
// Data           :   ebp Relative, [00000010], Param, Type: struct takePriority *, pPriority
// Data           :   ebp Relative, [00000014], Param, Type: class std::vector<StructMonster::VIRTUAL_PARTY,std::allocator<StructMonster::VIRTUAL_PARTY> > &, vPartyContribute
// Data           :   ebp Relative, [00000018], Param, Type: float, fDropRatePenalty
// Data           :   ebp Relative, [0000001C], Param, Type: float, fPCBangDropRateBonus
            Player player = null;

            fDropRatePenalty = GameRule.fGoldDropRate * fDropRatePenalty * fPCBangDropRateBonus;
            if (Globals.GetRandomInt32() % 100 >= this.m_pContentInfo.gold_drop_percentage * fDropRatePenalty)
                return;

            // this next section just calculates the penalty for gametime
            // we don't use this so it can be skipped
/*
            foreach (HateTag ht in this.m_vHateList)
            {
//         public uint uid;
//         public uint nTime;
//         public int nHate;
//         public bool bIsActive;
//         public int nBadAttackCount;
//         public int nLastMaxHate;
                if (ht.uid == 0)
                    goto LABEL_18;

                Creature cr = Creature.get(ht.uid) as Creature;
                if (cr != null)
                {
                    if (cr.IsPlayer())
                        player = cr as Player;
                    if (cr.IsSummon())
                        player = (cr as Summon).m_master;

                    if (player != null)
                    {
        LABEL_10:
                        if ((player.m_StatusFlag & StatusFlags.LoginComplete) != 0 && player.m_nLogoutTime != 0 && player.bIsInWorld)
                        {
                            *(v7 - 24) = 10000;
                            *(v7 - 20) = 0;
                        }
                        goto LABEL_17;
                    }
                }
        LABEL_17:
                *(v7 - 4) = -1;
                v8 = *(v7 - 16);
        LABEL_18:
                std::_Vector_const_iterator<_HATE_TAG_std::allocator<_HATE_TAG>>::operator__((v7 - 48));
                gold = v12;
                v49 = *(v12 + 8);
            }
*/

/*
            if ( c_fixed<10000>::operator__<int>((v7 - 24), 0) )
            {
                v17 = *(v7 + 12);
                if ( v17 )
                {
                    if ( (*(*v17 + 24))(*(v7 + 12)) )
                        goto LABEL_27;
                    if ( (*(*v17 + 40))(v17) )
                    {
                        v17 = *(v17 + 4140);
        LABEL_27:
                        if ( v17 && *(v17 + 1028) & 1 && !*(v17 + 4444) && *(v17 + 68) )
                        {
                            if ( StructPlayer::IsGameTimeLimited(v17) )
                            {
                                v18 = StructPlayer::GetContinuousPlayTime(v17);
                                GameRule::GetGameTimeLimitPenalty((v7 - 80), v18);
                                if ( c_fixed<10000>::operator<((v7 - 24), (v7 - 80)) )
                                {
                                    *(v7 - 24) = *(v7 - 80);
                                    *(v7 - 20) = *(v7 - 76);
                                }
                            }
                            else
                            {
                                *(v7 - 24) = 10000;
                                *(v7 - 20) = 0;
                            }
                        }
                    }
                }
            }
*/
//             if ( !c_fixed<10000>::operator__<int>((v7 - 24), 0) )
//             {
            gold = Globals.GetRandomInt32(this.m_pContentInfo.gold_min, this.m_pContentInfo.gold_max);
            if (gold < 0)
                gold = 1;

            if (gold > 1000000)
                gold = 1000000;
            if (this.m_nDungeonId != 0)
            {
                DungeonManager.Instance.GetTaxRate(this.m_nDungeonId, out tax, out nGuildID);
                tax = (int)(gold * tax) / 100;
                if (nGuildID != 0)
                    GuildManager.Instance.GiveTax(nGuildID, tax, 0);
                gold -= tax;
            }
            Item gi = MemoryPool.AllocGold(gold, ItemInstance.GenerateCode.ByMonster);
            gi.SetCurrentXY(pos.x, pos.y);
            gi.m_layer = this.m_layer;

            gi.AddNoise(Globals.GetRandomInt32(), Globals.GetRandomInt32(), 18);
            gi.SetPickupOrder(pPriority.PickupOrder);
            GameContent.MonsterDropItemToWorld(this, gi);
            int eventDropCode = GameContent.GetEventDropItemCode();

            if (eventDropCode != 0 && GameContent.IsValidItemCode(eventDropCode))
                this.dropItem(pos, pKiller, pPriority, vPartyContribute, eventDropCode, GameContent.GetEventDropItemCount(), 1, true, (int)GameContent.GetEventDropItemFlag());

            int activeDrop = EventItemManager.Instance.GetActiveDrop(Globals.GetArTime());

            if (activeDrop != 0)
            {
                if (GameContent.IsValidItemCode(activeDrop))
                {
                    this.dropItem(pos, pKiller, pPriority, vPartyContribute, activeDrop, 1, 1, true, -1);
                }
            }
//            }
        }

        protected void procDropItem(ArPosition pos, Creature pKiller, takePriority pPriority, List<VirtualParty> vPartyContribute, float fDropRatePenalty, float fPCBangDropRateBonus)
        {
            long item_count;

            foreach (MonsterBase.MonsterItemDropInfo drop in this.m_pContentInfo.item_drop_list)
            {
                if (drop.item_id != 0 && GameContent.checkDrop(pKiller, drop.item_id, drop.percentage, fDropRatePenalty, fPCBangDropRateBonus))
                {
                    item_count = Globals.GetRandomInt32(drop.min_count, drop.max_count);
                    if (item_count < drop.min_count || item_count > drop.max_count)
                    {
                        Globals.Log.Error("Monster.procDropItem: Min/Max Count error!");
                    }
                    else
                    {
                        int level = Globals.GetRandomInt32(drop.min_level, drop.max_level);
                        int code = drop.item_id;
                        if (code >= 0)
                            this.dropItem(pos, pKiller, pPriority, vPartyContribute, code, item_count, level, false, -1);
                        else
                            this.dropItemGroup(pos, pKiller, pPriority, vPartyContribute, code, item_count, level, -1);
                    }
                }
            }

/*

            for(int i = 0; i < 10; ++i)
            {
                if (this.m_pContentInfo.drop_item_id[i] != 0 && GameContent.checkDrop(pKiller, this.m_pContentInfo.drop_item_id[i], this.m_pContentInfo.drop_percentage[i], fDropRatePenalty, fPCBangDropRateBonus) )
                {
                    item_count = Globals.GetRandomInt32(this.m_pContentInfo.drop_min_count[i], this.m_pContentInfo.drop_max_count[i]);
                    if (item_count < this.m_pContentInfo.drop_min_count[i] || item_count > this.m_pContentInfo.drop_max_count[i])
                    {
                        Globals.Log.Error("Monster.procDropItem: Min/Max Count error!");
                    }
                    else
                    {
                        int level = Globals.GetRandomInt32(this.m_pContentInfo.drop_min_level[i], this.m_pContentInfo.drop_max_level[i]);
                        int code = this.m_pContentInfo.drop_item_id[i];
                        if (code >= 0 )
                            this.dropItem(pos,pKiller, pPriority, vPartyContribute, code, item_count, level, false,-1);
                        else
                            this.dropItemGroup(pos,pKiller,pPriority,vPartyContribute, code, item_count, level, -1);
                    }
                }
            }
*/

            this.procQuest(pos,pKiller,pPriority,vPartyContribute);
        }

// Function       :   protected const bool selectDropItems(class std::vector<int,std::allocator<int> > &, class std::vector<__int64,std::allocator<__int64> > &)

        protected void dropItemGroup(ArPosition pos, Creature pKiller, takePriority pPriority, List<VirtualParty> vPartyContribute, int nDropGroupID, long count, int level, int nFlagIndex)
        {
            Dictionary<int, long> mapDropItem = new Dictionary<int, long>();
            long nItemCount;
            int nItemID;
            for(int i = 0; i < count; ++i)
            {
                nItemID = nDropGroupID;
                nItemCount = 1;

                do
                    GameContent.SelectItemIDFromDropGroup(nItemID, out nItemID, out nItemCount);
                while (nItemID < 0 );
                if (nItemID > 0 )
                {
                    if(mapDropItem.ContainsKey(nItemID))
                    {
                        mapDropItem[nItemID] = mapDropItem[nItemID] + nItemCount;
                    }
                    else
                    {
                        mapDropItem.Add(nItemID, nItemCount);
                    }
                }
            }

            foreach(KeyValuePair<int, long> kvp in mapDropItem)
            {
                this.dropItem(pos,pKiller,pPriority, vPartyContribute, kvp.Key,kvp.Value, level, false, nFlagIndex);
            }
        }

        protected void dropItem(ArPosition pos, Creature pKiller, takePriority pPriority, List<VirtualParty> vPartyContribute, int code, long count, int level, bool bIsEventItem, int nFlagIndex)
        {
            Player player = null;
            Creature cr = null;

            if (count == 0)
            {
                Globals.Log.Error("dropItem: count was 0. (x: {0}, y: {1}, code: {2}, Killer: {3})",pos.x,pos.y,code,pKiller.GetName());
                return;
            }

            foreach (HateTag ht in this.m_vHateList)
            {
                if(ht.uid != 0)
                {
                    cr = Creature.get(ht.uid) as Creature;

                    if (cr != null)
                    {
                        if (cr.IsPlayer())
                            player = cr as Player;

                        if(cr.IsSummon())
                            player = (cr as Summon).m_master;

                        if (player != null && (player.m_StatusFlag & StatusFlags.LoginComplete) != 0 && player.m_nLogoutTime == 0 && player.bIsInWorld)
                            break;
                    }
                }
            }

            if(player == null)
            {
                if (pKiller == null)
                    return;
                if (pKiller.IsPlayer())
                    player = pKiller as Player;
                if (pKiller.IsSummon())
                    player = (pKiller as Summon).m_master;
            }

            if (player != null && (player.m_StatusFlag & StatusFlags.LoginComplete) != 0 && player.m_nLogoutTime == 0 && player.bIsInWorld)
            {
                Item ni = Item.AllocItem(0,code, count, ItemInstance.GenerateCode.ByMonster, level, -1,-1,-1,0,0,0,0,
                    -1,0,0,0,0);
                ni.SetCurrentXY(pos.x, pos.y);

                ni.m_layer = this.m_layer;

                ni.AddNoise(Globals.GetRandomInt32(), Globals.GetRandomInt32(), 18);
                ni.SetPickupOrder(pPriority.PickupOrder);

                if ((uint)nFlagIndex <= 0x1F)
                {
                    ni.m_Instance.Flag |= (uint)(1 << (nFlagIndex & 0x1F));
                }
                if (bIsEventItem)
                {
                    ni.m_bIsEventDrop = true;
                    ni.m_Instance.Flag |= 0x10;
                }
                GameContent.MonsterDropItemToWorld(this, ni);
            }
        }


        protected void calcPartyContribute(Creature pKiller, List<VirtualParty> vPartyContribute)
        {
            uint t;                                                                         // -16  -10h
            int nFirstAttackPartyID;                                                        // -104 -68h
            int nTamerPartyID;                                                              // -100 -64h
            float fMaxDamageAdd;                                                            // -96  -60h
            uint hKiller;                                                                   // -84  -54h
            int nLastAttackPartyID;                                                         // -80  -50h
            Dictionary<int ,calcPartyContributePartyDamage> mapPartyDamageContribute;       // -76  -4Ch    map is -44  -2Ch
            Player player;

            // itVector -20  -14h (VirtualParty)
            // itMap    -44  -2Ch (Dictionary<int ,calcPartyContributePartyDamage>)
            // it       -56  -38h (DamageTag)
            // pit      -64  -40h (Creature)

           
            float fContribute;// .text:004481D9 fContribute     = dword ptr  0Ch

//             v4 = this;
//             *(v3 - 48) = this;
//             v5 = &this.m_vDamageList;

            if (this.m_vDamageList.Count > 0)
            {
                t = Globals.GetArTime();
                hKiller = 0;
                mapPartyDamageContribute = new Dictionary<int ,calcPartyContributePartyDamage>();
                fMaxDamageAdd = 0.1f;
                nTamerPartyID = 0;
                nFirstAttackPartyID = 0;
                nLastAttackPartyID = 0;

                vPartyContribute.Capacity = this.m_vDamageList.Count;

                if (this.m_nFirstAttackTime + 6000 < t)
                {
                    this.m_hFirstAttacker = 0;
                    fMaxDamageAdd = 0.4f;
                }

                if (pKiller.IsSummon())
                {
                    player = (pKiller as Summon).m_master;
                }
                else if(pKiller.IsPlayer())
                {
                    player  = pKiller as Player;
                    if(player != null)
                    {
                        hKiller = player.m_hHandle;
                        nLastAttackPartyID = player.m_nPartyId;
                    }
                }
//                 std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
//                     (v3 - 28),
//                     &v4->m_vDamageList._Myfirst->uid,
//                     this.m_vDamageList.baseclass_0.___u0.baseclass_0);
//                 it = *(v3 - 28);
//                 *(v3 - 52) = *(v3 - 24);
                foreach (DamageTag dt in this.m_vDamageList)
                {
                    ///// HACK
                    Player p = Creature.get(dt.uid) as Player;
                    if (p != null)
                    {
                        VirtualParty vp = new VirtualParty(dt.uid, dt.nDamage,p.GetLevel());
                        vp.fContribute = 1.0f;
                        vPartyContribute.Add(vp);
                    }
                }
                return;
            }
                    /////
/*
                    std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                        (v3 - 28),
                        v49,
                        v50);
                    if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
                             (it),
                             (v3 - 28)) )
                    {
                        std::_Tree<std::_Tmap_traits<std::basic_string<char_std::char_traits<char>_std::allocator<char>>_XPropertySetBase<std::basic_string<char_std::char_traits<char>_std::allocator<char>>>::property_tag_std::less<std::basic_string<char_std::char_traits<char>_std::allocator<char>>>_std::allocator<std::pair<std::basic_string<char_std::char_traits<char>_std::allocator<char>>_const_XPropertySetBase<std::basic_string<char_std::char_traits<char>_std::allocator<char>>>::property_tag>>_0>>::const_iterator::const_iterator(
                            (v3 - 36),
                            **(v3 - 72),
                            (v3 - 76));
                        *(v3 - 44) = *(v3 - 36);
                        *(v3 - 40) = *(v3 - 32);
                        while ( 1 )
                        {
                            std::_Tree<std::_Tmap_traits<std::basic_string<char_std::char_traits<char>_std::allocator<char>>_XPropertySetBase<std::basic_string<char_std::char_traits<char>_std::allocator<char>>>::property_tag_std::less<std::basic_string<char_std::char_traits<char>_std::allocator<char>>>_std::allocator<std::pair<std::basic_string<char_std::char_traits<char>_std::allocator<char>>_const_XPropertySetBase<std::basic_string<char_std::char_traits<char>_std::allocator<char>>>::property_tag>>_0>>::const_iterator::const_iterator(
                                (v3 - 28),
                                *(v3 - 72),
                                (v3 - 76));
                            if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
                                     (v3 - 44),
                                     (v3 - 28)) )
                                break;
                            v34 = lvl;//std::_Tree<std::_Tmap_traits<int_int_std::less<int>_std::allocator<std::pair<int_const_int>>_0>>::const_iterator::operator_((v3 - 44));
                            v35 = damage;//std::_Tree<std::_Tmap_traits<int_int_std::less<int>_std::allocator<std::pair<int_const_int>>_0>>::const_iterator::operator_((v3 - 44));
                            v36 = id;//std::_Tree<std::_Tmap_traits<int_int_std::less<int>_std::allocator<std::pair<int_const_int>>_0>>::const_iterator::operator_((v3 - 44));

//             public int nPartyID;// Data           :     this+0x0, Member, Type: int, 
//             public uint hPlayer;// Data           :     this+0x4, Member, Type: unsigned int, 
//             public int nDamage;// Data           :     this+0x8, Member, Type: int, 
//             public float fContribute;// Data           :     this+0xC, Member, Type: float, 
//             public bool bTamer;// Data           :     this+0x10, Member, Type: bool, 
//             public int nLevel;// Data           :     this+0x14, Member, Type: int, 
//         public uint uid;
//         public uint nTime;
//         public int nDamage;

                            // 0,4,8

                            VirtualParty vp = new VirtualParty(id, damage, lvl);
                            vPartyContribute.Add(vp);
//                            __Inc_const_iterator____Tree_V___Tmap_traits_HUPARTY_DAMAGE__3__calcPartyContribute_StructMonster__IAEXPAUStructCreature__AAV__vector_UVIRTUAL_PARTY_StructMonster__V__allocator_UVIRTUAL_PARTY_StructMonster___std___std___Z_U__less_H_6_V__allocator_U__pair___CBHUPARTY_DAMAGE__3__calcPartyContribute_StructMonster__IAEXPAUStructCreature__AAV__vector_UVIRTUAL_PARTY_StructMonster__V__allocator_UVIRTUAL_PARTY_StructMonster___std___std___Z__std___6__0A__std___std__QAEXXZ((v3 - 44));
                        }
                        std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                            (v3 - 36),
                            *(v7 + 8),
                            v7);
                        std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                            (v3 - 28),
                            vPartyContribute*(v7 + 4),
                            vPartyContribute);
                        v38 = *(v3 - 32);
                        v39 = *(v3 - 24);
                        *(v3 - 92) = *(v3 - 36);
                        *(v3 - 36) = *(v3 - 28);
                        *(v3 - 88) = v38;
                        *(v3 - 32) = v39;
                        v40 = std::_Vector_const_iterator<_EXP_TABLE_std::allocator<_EXP_TABLE>>::operator_(
                                  (v3 - 92),
                                  (v3 - 36));
                        std::_Sort<StructMonster::VIRTUAL_PARTY___int_bool____cdecl____StructMonster::VIRTUAL_PARTY_const___StructMonster::VIRTUAL_PARTY_const___>(
                            v39,
                            v38,
                            v40,
                            Monster.VirtualParty.greaterByDamage);
                        std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                            (v3 - 36),
                            vPartyContribute(v7 + 4),
                            vPartyContribute);
                        *(v3 - 20) = *(v3 - 36);
                        *(v3 - 16) = *(v3 - 32);
                        while ( 1 )
                        {
                            VirtualParty vp3;
                            std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                                (v3 - 28),
                                *(v7 + 8),
                                vPartyContribute);
                            if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
                                     (v3 - 20),
                                     (v3 - 28)) )
                            {
                                __Tidy____Tree_V___Tmap_traits_HUPARTY_DAMAGE__3__calcPartyContribute_StructMonster__IAEXPAUStructCreature__AAV__vector_UVIRTUAL_PARTY_StructMonster__V__allocator_UVIRTUAL_PARTY_StructMonster___std___std___Z_U__less_H_6_V__allocator_U__pair___CBHUPARTY_DAMAGE__3__calcPartyContribute_StructMonster__IAEXPAUStructCreature__AAV__vector_UVIRTUAL_PARTY_StructMonster__V__allocator_UVIRTUAL_PARTY_StructMonster___std___std___Z__std___6__0A__std___std__IAEXXZ((v3 - 76));
                                return;
                            }

                            fContribute = 0.0f;
                            if (nTamerPartyID != 0 && nTamerPartyID == vp3.nPartyID)
                                vp3.bTamer = true;

                            if (this.m_nTotalDamage != 0)
                                fContribute = (float)vp3.nDamage / (float)this.m_nTotalDamage * 0.5f;
                            std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                                (v3 - 112),
                                *(v7 + 4),
                                vPartyContribute);
                            if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
                                     (v3 - 20),
                                     (v3 - 112)) )
                                fContribute = fContribute + fMaxDamageAdd;

                            if (nFirstAttackPartyID != 0)
                            {
                                if(vp3.nPartyID == nFirstAttackPartyID)
                                {
                                    fContribute = fContribute + 0.3f;
                                }
                            }
                            else if (this.m_hFirstAttacker != 0)
                            {
                                if(vp3.hPlayer == this.m_hFirstAttacker)
                                {
                                    fContribute = fContribute + 0.3f;
                                }
                            }

                            if (nLastAttackPartyID != 0)
                            {
                                if(vp3.nPartyID == nLastAttackPartyID)
                                    fContribute = fContribute + 0.1f;
                            }
                            else
                            {
                                if(vp3.hPlayer == hKiller)
                                    fContribute = fContribute + 0.1f;
                            }
                            vp3.fContribute = fContribute;
                        }
                    }
                    Creature c11 = Creature.get(dt.uid) as Creature;

                    if (c11 == null)
                    {
                        goto LABEL_33;
                    }
                    v12 = c11.IsPlayer() ? v11 : null;
                    v13 = c11.IsSummon() ? v11 : null;
                    if (c11.IsPlayer())
                    {
                        player = c11 as Player;
                    }
                    if ( v13 != null)
                        break;
        LABEL_32:
                    v4 = *(v3 - 48);
        LABEL_33:
                }
                v12 = *(v13 + 4140);
        LABEL_15:
                if (v12.m_nPartyId != 0)
                {
                    if (this.m_hTamer == v12.m_hHandle)
                        nTamerPartyID = v12.m_nPartyId;

                    v14 = _find____Tree_V___Tmap_traits_HUPARTY_DAMAGE__3__calcPartyContribute_StructMonster__IAEXPAUStructCreature__AAV__vector_UVIRTUAL_PARTY_StructMonster__V__allocator_UVIRTUAL_PARTY_StructMonster___std___std___Z_U__less_H_6_V__allocator_U__pair___CBHUPARTY_DAMAGE__3__calcPartyContribute_StructMonster__IAEXPAUStructCreature__AAV__vector_UVIRTUAL_PARTY_StructMonster__V__allocator_UVIRTUAL_PARTY_StructMonster___std___std___Z__std___6__0A__std___std__QAE_AViterator_12_ABH_Z(
                              (v3 - 76),
                              (v3 - 128),
                              v12.m_nPartyId);
                    v15 = v14->baseclass_0.baseclass_0.baseclass_0._Mycont;
                    *(v3 - 40) = v14->baseclass_0._Ptr;
                    v16 = *(v3 - 72);
                    *(v3 - 44) = v15;
                    std::_Tree<std::_Tmap_traits<std::basic_string<char_std::char_traits<char>_std::allocator<char>>_XPropertySetBase<std::basic_string<char_std::char_traits<char>_std::allocator<char>>>::property_tag_std::less<std::basic_string<char_std::char_traits<char>_std::allocator<char>>>_std::allocator<std::pair<std::basic_string<char_std::char_traits<char>_std::allocator<char>>_const_XPropertySetBase<std::basic_string<char_std::char_traits<char>_std::allocator<char>>>::property_tag>>_0>>::const_iterator::const_iterator(
                        (v3 - 120),
                        v16,
                        (v3 - 76));
                    if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
                             (v3 - 44),
                             (v3 - 120)) )
                    {

                        v17 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((v3 - 56));
                        v18 = v12.GetLevel();
                        v19 = LODWORD(v17->end.z);
                        *(v3 + 8) = v12.GetLevel();
                        v20 = __A__map_HUPARTY_DAMAGE__3__calcPartyContribute_StructMonster__IAEXPAUStructCreature__AAV__vector_UVIRTUAL_PARTY_StructMonster__V__allocator_UVIRTUAL_PARTY_StructMonster___std___std___Z_U__less_H_6_V__allocator_U__pair___CBHUPARTY_DAMAGE__3__calcPartyContribute_StructMonster__IAEXPAUStructCreature__AAV__vector_UVIRTUAL_PARTY_StructMonster__V__allocator_UVIRTUAL_PARTY_StructMonster___std___std___Z__std___6__std__QAEAAUPARTY_DAMAGE__3__calcPartyContribute_StructMonster__IAEXPAUStructCreature__AAV__vector_UVI(
                                  (v3 - 76),
                                  v12.m_nPartyId);
                        v21 = *(v3 + 8);
                        v20->nDamage = v19;
                        v20->nLevel = v12.GetLevel();
                    }
                    else
                    {
                        v22 = std::_Tree<std::_Tmap_traits<int_int_std::less<int>_std::allocator<std::pair<int_const_int>>_0>>::const_iterator::operator_((v3 - 44))
                            + 1;
                        *v22 = (*v22
                              + LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((v3 - 56))->end.z));
                        v23 = std::_Tree<std::_Tmap_traits<int_int_std::less<int>_std::allocator<std::pair<int_const_int>>_0>>::const_iterator::operator_((v3 - 44));
                        if ( *(v23 + 2) < v12.GetLevel())
                        {
                            v24 = std::_Tree<std::_Tmap_traits<int_int_std::less<int>_std::allocator<std::pair<int_const_int>>_0>>::const_iterator::operator_((v3 - 44));
                            *(v24 + 2) = v12.GetLevel();
                        }
                    }
                    if (v12.m_hHandle == (v3 - 48).m_hFirstAttacker))
                        nFirstAttackPartyID = v12.m_nPartyId;
                }
                else
                {
                    std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                        (v3 - 36),
                        *(v7 + 4),
                        v7);
                    *(v3 - 20) = *(v3 - 36);
                    *(v3 - 16) = *(v3 - 32);
                    while ( 1 )
                    {
                        std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                            (v3 - 92),
                            *(v7 + 8),
                            v7);
                        if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
                                 (v3 - 20),
                                 (v3 - 92)) )
                            goto LABEL_30;
                        v25 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((v3 - 20));
                        v26 = v12.m_hHandle;
                        v27 = (v3 - 20);
                        VirtualParty vp2; // this is iterator here
                        
                        if (vp2.hPlayer == v12.m_hHandle)
                            break;
                        std::_Vector_const_iterator<_HATE_TAG_std::allocator<_HATE_TAG>>::operator__(v27);
                    }
                    v28 = &std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(v27)->end.z;
                    *v28 += LODWORD(std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((v3 - 56))->end.z);
        LABEL_30:
                    std::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>::_Vector_const_iterator<StateDamage_std::allocator<StateDamage>>(
                        (v3 - 112),
                        *(v7 + 8),
                        v7);
                    if ( std::_Vector_const_iterator<X2D::Point<float>_std::allocator<X2D::Point<float>>>::operator__(
                             (v3 - 20),
                             (v3 - 112)) )
                    {
                        v29 = std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_((v3 - 56));
                        VirtualParty vp = new VirtualParty(v12.m_hHandle, v29->end.z, v12.GetLevel());
                        vPartyContribute.Add(vp);
                    }
                }
                goto LABEL_32;
            }
 */
        }

// Function       :   protected void procImmoralPoint(class std::vector<StructMonster::VIRTUAL_PARTY,std::allocator<StructMonster::VIRTUAL_PARTY> > &)
        public uint m_hTamer;                                                   // 0xFE0
        public int m_nTamedTime;                                               // 0xFE4
        public bool m_bTamedSuccess;                                            // 0xFE8
        public int m_nTamingSkillLevel;                                         // 0xFEC
        public uint m_nLastTrackTime;                                           // 0xFF0
        public uint m_nHateCheckTime;                                           // 0xFF4
        public uint m_hFirstAttacker;                                           // 0xFF8
        public uint m_nFirstAttackTime;                                         // 0xFFC
        public List<DamageTag> m_vDamageList = new List<DamageTag>();           // 0x1000
        public List<HateTag> m_vHateList = new List<HateTag>();                 // 0x1010
        public List<HateModifierTag> m_vHateModifierByState = new List<HateModifierTag>();  // 0x1020
        public bool m_bNeedToFindEnemy;                                         // 0x1030
        public int m_nMaxHate;                                                  // 0x1034
        public uint m_nLastHateUpdateTime;                                      // 0x1038
        public bool m_bComeBackHome;                                            // 0x103C
        public uint m_nRegenTime;                                               // 0x1040
        public bool m_bRespawnByScript;                                         // 0x1044
        public float m_nLastEnemyDistance;                                      // 0x1048

// Function       :   protected void StructMonster::applyState(struct StructState &)

        protected override void onBeforeCalculateStat()
        {
            if ((this.m_StatusFlag & StatusFlags.MoveSpeedFixed) == 0)
                this.m_Attribute.nMoveSpeed += (this.m_pContentInfo.run_speed - 120);

            this.m_Attribute.nAttackRange = (this.m_pContentInfo.attack_range);
            this.m_fDetectHideRange = this.m_pContentInfo.hidesense_range;
            this.m_vHateModifierByState.Clear();
        }

        protected override void onApplyAttributeAdjustment()
        {
            this.m_nMaxHP += this.m_pContentInfo.hp;
            this.m_nMaxMP += this.m_pContentInfo.mp;
            this.m_Attribute.nAttackPointRight += (this.m_pContentInfo.attack_point);
            this.m_Attribute.nMagicPoint += (this.m_pContentInfo.magic_point);
            this.m_Attribute.nDefence += (this.m_pContentInfo.defence);
            this.m_Attribute.nMagicDefence += (this.m_pContentInfo.magic_defence);
            this.m_Attribute.nAttackSpeedRight += (this.m_pContentInfo.attack_speed);
            this.m_Attribute.nAttackSpeedLeft += (this.m_pContentInfo.attack_speed);
            this.m_Attribute.nCastingSpeed += (this.m_pContentInfo.casting_speed);
            this.m_Attribute.nAccuracyRight += (this.m_pContentInfo.accuracy);
            this.m_Attribute.nAccuracyLeft += (this.m_pContentInfo.accuracy);
            this.m_Attribute.nAvoid += (this.m_pContentInfo.avoid);
            this.m_Attribute.nMagicAccuracy += (this.m_pContentInfo.magic_accuracy);
            this.m_Attribute.nMagicAvoid += (this.m_pContentInfo.magic_avoid);
        }

        protected override void onCompleteCalculateStat()
        {
            if (this.m_bIsDungeonRaidMonster)
                this.m_Attribute.nMoveSpeed = ((float)this.m_Attribute.nMoveSpeed * 1.5f);
        }

        protected override void onDead(Creature pFrom, bool decreaseEXPOnDead)
        {
            uint ct;

            takePriority Priority = new takePriority();              // 100 64
            ArPosition pos;                     // 70 4c
            List<VirtualParty> vPartyContribute = new List<VirtualParty>(); // 60  3c
// .text:004489E4 pit             = StructPlayer::iterator ptr -28h 40
// .text:004489E4 itEnemy         = StructCreature::iterator ptr -20h 32
// .text:004489E4 var_18          = dword ptr -18h 24
            float fChaosDropRateBonus;          // 28 1c
            float fGoldDropRateBonus;           // 24 18
            float fDropRatePenalty;             // 20 14
            float fItemDropRateBonus;           // 16 10

            Player player;

// Data           :   ebp Relative, [FFFFFFC4], Local, Type: class std::vector<StructMonster::VIRTUAL_PARTY,std::allocator<StructMonster::VIRTUAL_PARTY> >, vPartyContribute
// Data           :   ebp Relative, [FFFFFFD8], Local, Type: class std::_Vector_iterator<_HATE_TAG,std::allocator<_HATE_TAG> >, it
// Data           :   ebp Relative, [FFFFFFD8], Local, Type: struct StructPlayer::iterator, it
// Data           :   ebp Relative, [FFFFFFB4], Local, Type: struct ArPosition, pos
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: class std::_Vector_iterator<StructMonster::VIRTUAL_PARTY,std::allocator<StructMonster::VIRTUAL_PARTY> >, itContribute
// Data           :   ebp Relative, [FFFFFF9C], Local, Type: struct takePriority, Priority
// Data           :   ebp Relative, [FFFFFFEC], Local, Type: float, fChaosDropRateBonus
// Data           :   ebp Relative, [FFFFFFE4], Local, Type: float, fGoldDropRateBonus
// Data           :   ebp Relative, [FFFFFFF0], Local, Type: float, fDropRatePenalty
// Data           :   ebp Relative, [FFFFFFDC], Local, Type: float, fItemDropRateBonus
// Data           :   ebp Relative, [FFFFFFD8], Local, Type: struct StructPlayer::iterator, pit
// Typedef        :   StructMonster::onDead::__l45::partyPCBangBonusChecker, Type: struct StructMonster::onDead::__l45::partyPCBangBonusChecker
// Data           :   ebp Relative, [FFFFFFD4], Local, Type: struct StructMonster::onDead::__l45::partyPCBangBonusChecker, _fo
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: struct StructCreature::iterator, itEnemy

            int i;

            player = pFrom as Player;
            base.onDead(pFrom, decreaseEXPOnDead);
            this.SetStatus(MonsterStatus.Dead);
            this.quadTreeItem.RemoveMe();

            this.m_bTamedSuccess = false;
            if (this.m_hTamer != 0)
            {
                Player p = Player.get(this.m_hTamer) as Player;
                if (p != null)
                    this.m_bTamedSuccess = GameContent.ProcTame(this);
            }

            this.calcPartyContribute(pFrom, vPartyContribute);
            this.procEXP(pFrom, vPartyContribute);
            if (!this.m_bTamedSuccess )
            {
                vPartyContribute.Sort(new VirtualPartySorter(VirtualPartySorter.VirtualPartySorterOptions.Contribute));

                ct = Globals.GetArTime();
                pos = this.GetCurrentPosition(ct);

                i = 0;
                foreach (VirtualParty vp in vPartyContribute)
                {
                    if (this.m_bIsDungeonRaidMonster && this.m_pContentInfo.monster_type >= 31)
                    {
                        Priority.PickupOrder.hPlayer[i] = 0;
                        Priority.PickupOrder.nPartyID[i] = 0;
                    }
                    else if (vp.hPlayer != 0)
                    {
                        Priority.PickupOrder.hPlayer[i] = vp.hPlayer;
                        Priority.PickupOrder.nPartyID[i] = 0;
                    }
                    else
                    {
                        Priority.PickupOrder.hPlayer[i] = 0;
                        Priority.PickupOrder.nPartyID[i] = vp.nPartyID;
                    }

                    i++;
                    if(i >= 3)
                        break;
                }

                int cl;
                if (vPartyContribute.Count > 0)
                    cl = vPartyContribute[0].nLevel;
                else
                    cl = 0;
//                 if (vPartyContribute.Count > 0)
//                     std::_Vector_const_iterator<PartyManager::PartyInfo___std::allocator<PartyManager::PartyInfo__>>::operator_(itEnemy);

                // level-based drop penalty
                // anything 5 levels or below won't drop as often as higher levels
                fDropRatePenalty = 1.0f;
                cl -= this.GetLevel();
                if (cl >= 5 )
                {
                    fDropRatePenalty = 1.0f - (float)Math.Pow(cl-3, 2.0f) * 0.02f;
                    if (fDropRatePenalty < 0.0f )
                        fDropRatePenalty = 0.0f;
                }

                bool bIsPCBang = false;

                if (vPartyContribute.Count > 0)
                {
                    if (vPartyContribute[0].hPlayer != 0)
                    {
                        player = Player.get(vPartyContribute[0].hPlayer) as Player;
                        bIsPCBang = player != null && player.GetPCBangMode() == 2;
                    }
                    else
                    {
                        if (vPartyContribute[0].nPartyID != 0)
                        {
                            partyPCBangBonusChecker fn = new partyPCBangBonusChecker();
                            fn.m_posKiller = pos;
                            fn.m_bPremiumPCBang = false;

                            PartyManager.Instance.DoEachMember(vPartyContribute[0].nPartyID, fn);
                            bIsPCBang = fn.m_bPremiumPCBang;
                        }
                    }
                }
                else
                {
                    if(pFrom.IsPlayer())
                    {
                        player = pFrom as Player;
                    }
                    else if (pFrom.IsSummon())
                    {
                        Summon summon1 = pFrom as Summon;
                        player = summon1.m_master;
                    }

                    bIsPCBang = true;
                    if (player == null || player.GetPCBangMode() != 2)
                        bIsPCBang = false;
                }

                fChaosDropRateBonus = 1.0f;
                fItemDropRateBonus = 1.0f;
                fGoldDropRateBonus = 1.0f;
                if (bIsPCBang)
                {
                    fGoldDropRateBonus = GameRule.fPremiumPCBangGoldBonusDropRate;
                    fItemDropRateBonus = GameRule.fPremiumPCBangItemBonusDropRate;
                    fChaosDropRateBonus = GameRule.fPremiumPCBangChaosBonusDropRate;
                }

                player = pFrom as Player;
                this.procDropChaos(pFrom, Priority, vPartyContribute, fDropRatePenalty, fChaosDropRateBonus);
                if (pFrom.IsPlayer() && player.m_nChaos < 1 && player.GetQuestProgress(1032) == 1)
                    GameContent.addChaos(this, player, 1.0f);

                if (!this.m_bIsDungeonRaidMonster || this.m_pContentInfo.monster_type < 31)
                {
                    this.procDropGold(pos, pFrom, Priority, vPartyContribute, fDropRatePenalty, fGoldDropRateBonus);
                    this.procDropItem(pos, pFrom, Priority, vPartyContribute, fDropRatePenalty, fItemDropRateBonus);
                }
            }

            base.onDead(pFrom, decreaseEXPOnDead);

            foreach (HateTag ht in this.m_vHateList)
            {
                Creature hc = Creature.get(ht.uid) as Creature;
                if (hc != null)
                {
                    hc.RemoveFromEnemyList(this.m_hHandle);
                }
            }

            if (player != null && !String.IsNullOrEmpty(this.strOnDeathScript))
                LuaVM.Instance.RunString(player, this.strOnDeathScript);
        }

        protected void procQuest(ArPosition pos, Creature pKiller, takePriority pPriority, List<Monster.VirtualParty> vPartyContribute)
        {
            List<Quest> vQuestList = new List<Quest>();     // -96 -60h
            List<Player> vPlayer = new List<Player>();      // -68 -44h
//.text:00448E7E it              = std::_Vector_iterator<StructQuest *,std::allocator<StructQuest *> > ptr -28 -1Ch
            Player pPlayer;                                 // -16 -10h
// .text:00448E7E pos             = dword ptr  8  08h
// .text:00448E7E pKiller         = dword ptr  12 0Ch
// .text:00448E7E pPriority       = dword ptr  16 10h
// .text:00448E7E vPartyContribute= dword ptr  20 14h


            if (vPartyContribute.Count > 0)
            {
                if (vPartyContribute.First().hPlayer != 0)
                {
                    pPlayer = Player.get(vPartyContribute.First().hPlayer) as Player;
                    if (pPlayer != null)
                        vPlayer.Add(pPlayer);
                }
                else
                {
                    // it's a party, not a single player
//                    fn =  ::::myPartyFunctor::myPartyFunctor(vQuestList, this.m_nDeadTime, pos,vPlayer);
//                    PartyManager.Instance.DoEachMember(vPartyContribute.First().nPartyID, fn);
                }

                foreach (Player p in vPlayer)
                {
                    p.UpdateQuestStatusByMonsterKill(this.m_pContentInfo.uid);
                    vQuestList.Clear();
                    p.GetQuestByMonster(this.m_pContentInfo.uid, vQuestList, 4112);

                    foreach (Quest q in vQuestList)
                    {
                        if (q != null && q.m_QuestBase.nDropGroupId != 0)
                        {
                            if (!q.IsFinishable())
                            {
                                this.dropItemGroup(pos, pKiller, pPriority, vPartyContribute, q.m_QuestBase.nDropGroupId, 1, 1, -1);
                            }
                        }
                    }
                }
            }
        }


        protected void procEXP(Creature pKiller, List<VirtualParty> vPartyContribute)
        {
            float fSharedJP;
            float fSharedEXP;

            if (this.m_vDamageList.Count > 0)
            {
                foreach (VirtualParty vp in vPartyContribute)
                {
                    fSharedEXP = vp.fContribute * this.m_pContentInfo.exp;
                    fSharedJP = vp.fContribute * this.m_pContentInfo.jp;
                    if (fSharedEXP < 1)
                        fSharedEXP = 1;

                    if(vp.bTamer || (vp.hPlayer != 0 && vp.hPlayer == this.m_hTamer))
                    {
                        fSharedEXP = fSharedEXP * this.m_pContentInfo.taming_exp_adjust;
                        fSharedJP = fSharedJP * this.m_pContentInfo.taming_exp_adjust;
                    }

                    if (vp.hPlayer != 0)
                    {
                        Player player2 = Player.get(vp.hPlayer) as Player;
                        if (player2 != null)
                        {
                            GameContent.addEXP(this, player2, fSharedEXP, fSharedJP);
                        }
                    }
                    else
                    {
                        GameContent.addEXP(this, vp.nPartyID, (int)fSharedEXP, (int)fSharedJP);
                    }
                }
            }
        }

        protected void comeBackHome(bool bInvincible)
        {
            List<ArPosition> pl;
            if (this.IsMovable() && (this.m_StatusFlag & StatusFlags.Feared) == 0 || this.IsAutoTrap())
            {
                this.SetStatus(MonsterStatus.Normal);
                this.m_nLastHateUpdateTime = Globals.GetArTime();
                this.updateHate();
                this.m_nLastEnemyDistance = 0.0f;
                this.m_hEnemy = 0;
                this.m_nMaxHate = 0;
                this.m_bComeBackHome = true;

                pl = new List<ArPosition>();
                pl.Add(new ArPosition(this.m_RespawnX, this.m_RespawnY, 0));
                if (bInvincible)
                    this.m_StatusFlag |= StatusFlags.Invincible;

                this.SetPendingMove(pl, (byte)(2 * this.GetMoveSpeed() / 7));
            }
        }

        public override string ToString()
        {
            return String.Format("Monster: {0}", GameContent.GetString(this.m_pContentInfo.name_id));
        }
        

        public MonsterBase m_pContentInfo;                                      // 0x104C
        public int m_nTotalDamage;                                              // 0x1054
        public int m_nStatus;                                                   // 0x1058
        public int m_nGenerateCode;                                             // 0x105C
        public bool m_bIsWandering;                                             // 0x1060
        public float m_RespawnX;                                                // 0x1064
        public float m_RespawnY;                                                // 0x1068
        public bool m_bNeedToSetReturnPos;                                      // 0x106C
        public IMonsterDeleteHandler m_pDeleteHandler;// 0x1070
        public int m_nDungeonId;                                                // 0x1074
        public bool m_bIsDungeonRaidMonster;                                    // 0x1078
        public bool m_bIsDungeonOwnerGuardian;                                  // 0x1079
        public bool m_bIsDungeonSiegerGuardian;                                 // 0x107A
        public int m_nHuntaholicRespawnID;                                      // 0x107C
//        public List<X2D.Polygoni> m_pathFindPolygons = new List<X2D.Polygoni>();// 0x1080
        public int[] m_vTriggerFlag = new int[6];                               // 0x1090
        public GameContent.WayPointInfo m_pWayPointInfo;                        // 0x10A8
        public int m_nWayPointIdx;                                              // 0x10AC
        public Roamer m_pRoamer;                                                // 0x10B0
        public bool m_bContinueAttack;                                          // 0x10B4
        public uint m_hParent;
        public string strOnDeathScript = "";
    }

    public class DamageTag
    {
        public DamageTag(uint _uid, uint _time, int _damage)
        {
            uid = _uid;
            nTime = _time;
            nDamage = _damage;
        }
        
        public uint uid;
        public uint nTime;
        public int nDamage;
    }

    public class HateTag
    {
        public HateTag(uint _uid, uint _time, int _hate)
        {
            uid = _uid;
            nTime = _time;
            nHate = _hate;
        }

        public uint uid;
        public uint nTime;
        public int nHate;
        public bool bIsActive;
        public int nBadAttackCount;
        public int nLastMaxHate;
    }

    public class HateModifierTag
    {
        public HateModifierTag(uint _uid, int _hate)
        {
            uid = _uid;
            nHate = _hate;
        }

        public uint uid;
        public int nHate;
    }



}
